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

发布于 2024-10-17 11:34:56 字数 2680 浏览 2 评论 0原文

这个问题是关于 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;
    }
  }
}

>但是我还是想知道是否有更好的解决方案。

This question is about event handling on Android. It is not specific to c++.

I need to process UI/OS events, without blocking when all events have been processed.

The reason is that the application I am porting is very large and can't easily be rewritten to deal with its own stuff on a worker thread. Instead the application engine asks for UI/OS events to be processed during long-winded operations that would otherwise be blocking.

I have found that ALooper_pollAll(...) doesn't do this for me. If I, for example, create a dialog in my activity and start a long operation, ALooper_pollAll() won't make my dialog appear - it will show only when I return to the main loop (I tested this in onNativeWindowCreated).

The only solution that I have found to almost work is to do an inner loop on the UI thread, by calling the following code through 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
      }
    }
  }
}

This is, however, not an optimal solution, because it will not loop until there would be no more events to process (because events may be created during the run of the loop).

During my research I have found that I can get the MessageQueue from the Looper and add an IdleHandler that can quit my inner loop. I haven't tried this yet, there has to be a better way.

Given the fact that this is the architecture I must stick with, what is a better solution?

Update:

Using the MessageQueue I'm able to achieve what I need:

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

However, I still would like to know if there is a better solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝眼泪 2024-10-24 11:34:56

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

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

来自文档:

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

Not sure if I understood the question correctly but have you tried using an IntentService?

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

From the docs:

This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文