如何在 Android 上进行非阻塞事件处理?
这个问题是关于 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不确定我是否正确理解了这个问题,但是您尝试过使用 IntentService 吗?
http://developer.android.com/reference/android/app/IntentService.html
来自文档:
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: