如何在Android上进行非阻塞事件处理?

时间:2011-02-14 15:59:26

标签: android events java-native-interface message-queue looper

此问题与Android上的事件处理有关。它不是特定于c ++。

我需要处理UI / OS事件,而不是在处理完所有事件时阻塞。

原因是我移植的应用程序非常大,无法轻易地重写以处理工作线程上的自己的东西。相反,应用程序引擎要求在冗长的操作期间处理UI / OS事件,否则这些操作将被阻止。

我发现ALooper_pollAll(...)不会为我这样做。例如,如果我在我的活动中创建一个对话框并开始一个长操作,ALooper_pollAll()将不会显示我的对话框 - 它只会在我返回主循环时显示(我在onNativeWindowCreated中对此进行了测试)。

我发现几乎可以解决的唯一解决方案是在UI线程上执行内部循环,通过JNI调用以下代码:

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
      }
    }
  }
}

然而,这不是最佳解决方案,因为它不会循环,直到没有更多事件要处理(因为事件可能在循环运行期间创建)。

在我的研究中,我发现我可以从Looper获取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;
    }
  }
}

但是,我仍然想知道是否有更好的解决方案。

1 个答案:

答案 0 :(得分:0)

我不确定我是否正确理解了这个问题,但您是否尝试过使用IntentService?

http://developer.android.com/reference/android/app/IntentService.html

来自文档:

  

此“工作队列处理器”模式通常用于从应用程序的主线程卸载任务。 IntentService类的存在是为了简化这种模式并处理机制。“