この質問は、Android でのイベント処理に関するものです。これは c++ に固有のものではありません。
すべてのイベントが処理されたときにブロックせずに、UI/OS イベントを処理する必要があります。
その理由は、移植しようとしているアプリケーションが非常に大きく、ワーカー スレッドで独自のものを処理するように簡単に書き直すことができないためです。代わりに、アプリケーション エンジンは、他の方法ではブロックされるような時間のかかる操作中に、UI/OS イベントを処理するように要求します。
ALooper_pollAll(...) がこれを行わないことがわかりました。たとえば、アクティビティでダイアログを作成して長い操作を開始した場合、ALooper_pollAll() はダイアログを表示しません。メイン ループに戻ったときにのみ表示されます (onNativeWindowCreated でテストしました)。
ほとんど機能することがわかった唯一の解決策は、JNI を介して次のコードを呼び出して、UI スレッドで内部ループを実行することです。
public class MyActivity extends NativeActivity {
private Handler _uiEventsHandler = null;
private Runnable _uiEventsTask = new Runnable() {
public void run() {
Looper looper = Looper.myLooper();
looper.quit();
_uiEventsHandler.removeCallbacks(this);
_uiEventsHandler = null;
}
};
public void ProcessEvents(int timeout)
{
if (_uiEventsHandler==null) {
Looper looper = Looper.myLooper();
_uiEventsHandler = new Handler(looper);
_uiEventsHandler.removeCallbacks(_uiEventsTask);
//_uiEventsHandler.postDelayed(_uiEventsTask,timeout);
_uiEventsHandler.post(_uiEventsTask);
try {
looper.loop();
} catch (RuntimeException re) {
// We get an exception when we try to quit the loop, but the inner loop actually terminates
}
}
}
}
ただし、これは最適な解決策ではありません。処理するイベントがなくなるまでループしないためです (ループの実行中にイベントが作成される可能性があるため)。
調査中に、ルーパーから MessageQueue を取得し、内部ループを終了できる IdleHandler を追加できることがわかりました。私はまだこれを試していません。もっと良い方法があるはずです。
これが私が固執しなければならないアーキテクチャであるという事実を考えると、より良い解決策は何ですか?
アップデート:
MessageQueue を使用して、必要なものを達成できます。
public class MyActivity extends NativeActivity {
private class IdleHandler implements MessageQueue.IdleHandler {
private Looper _looper;
protected IdleHandler(Looper looper) {
_looper = looper;
}
public boolean queueIdle() {
_uiEventsHandler = new Handler(_looper);
_uiEventsHandler.post(_uiEventsTask);
return(false);
}
};
private boolean _processingEventsf = false;
private Handler _uiEventsHandler = null;
private Runnable _uiEventsTask = new Runnable() {
public void run() {
Looper looper = Looper.myLooper();
looper.quit();
_uiEventsHandler.removeCallbacks(this);
_uiEventsHandler = null;
}
};
public void ProcessEvents()
{
if (!_processingEventsf) {
Looper looper = Looper.myLooper();
looper.myQueue().addIdleHandler(new IdleHandler(looper));
_processingEventsf = true;
try {
looper.loop();
} catch (RuntimeException re) {
// We get an exception when we try to quit the loop.
}
_processingEventsf = false;
}
}
}
ただし、より良い解決策があるかどうかを知りたいです。