在调用另一个线程的处理程序之前,如何确保它不为空?
有一天,当我的程序尝试使用在另一个线程上创建的处理程序向该线程发送消息时,它抛出了 NullPointerException。尽管调用线程已经在另一个线程上调用了 start,但另一个线程创建的 Handler 尚未创建,或者对于调用线程尚不可见。这种情况很少发生。几乎每次测试运行都没有出现异常。
我想知道最好的方法是什么,以最小的复杂性和性能损失来避免这个问题。该程序是一个游戏,对性能非常敏感,尤其是在运行时。因此,例如,我尝试避免在设置后使用同步,并且更愿意避免随时旋转变量。
背景:
在 Android 中,Handler 类可用于“将要在与您自己的线程不同的线程上执行的操作排队”。文档在这里:
http://developer.android.com/intl/de/reference /android/os/Handler.html
Handler 必须在使用它的线程上创建。因此,在线程的构造函数中创建它(该线程由创建该线程的线程运行)不是一种选择。
当Handler用于UI线程以外的线程时,还必须使用Looper类:
http://developer.android.com/intl/de/reference /android/os/Looper.html
文档给出了为此目的使用两个类的示例:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
我非常丑陋的解决方法目前看起来像这样:
public class LooperThread extends Thread {
public volatile Handler mHandler;
public final ArrayBlockingQueue<Object> setupComplete = new ArrayBlockingQueue<Object>(1);
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
setupComplete();
Looper.loop();
}
public void waitForSetupComplete() {
while ( true ) {
try {
setupComplete.take();
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
private void setupComplete() {
while( true ) {
try {
setupComplete.put(new Object());
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
}
创建线程中的代码看起来像这样:
LooperThread otherThread = new LooperThread();
otherThread.start();
otherThread.waitForSetupComplete();
otherThread.mHandler.sendEmptyMessage(0);
有没有更好的方法解决方案?谢谢。
My program threw a NullPointerException the other day when it tried to use a Handler created on another thread to send that thread a message. The Handler created by the other thread was not yet created, or not yet visible to the calling thread, despite the calling thread having already called start on the other thread. This only happens very rarely. Almost every test run does not get the exception.
I was wondering what the best way is to avoid this problem for sure with minimal complication and performance penalty. The program is a game and very performance sensitive, especially once it is running. Therefore I try to avoid using synchronization after setup, for example, and would prefer to avoid spinning on a variable at any time.
Background:
In Android the Handler class may be used to "enqueue an action to be performed on a different thread than your own". Documentation here:
http://developer.android.com/intl/de/reference/android/os/Handler.html
The Handler must be created on the thread where it will be used. So creating it in the constructor of a thread, which is run by the thread creating that thread, is not an option.
When the Handler is for a thread other than the UI thread, the Looper class must also be used:
http://developer.android.com/intl/de/reference/android/os/Looper.html
The documentation gives this example of using the two classes for this purpose:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
My very ugly workaround currently looks like this:
public class LooperThread extends Thread {
public volatile Handler mHandler;
public final ArrayBlockingQueue<Object> setupComplete = new ArrayBlockingQueue<Object>(1);
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
setupComplete();
Looper.loop();
}
public void waitForSetupComplete() {
while ( true ) {
try {
setupComplete.take();
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
private void setupComplete() {
while( true ) {
try {
setupComplete.put(new Object());
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
}
With the code in the creating thread looking like this:
LooperThread otherThread = new LooperThread();
otherThread.start();
otherThread.waitForSetupComplete();
otherThread.mHandler.sendEmptyMessage(0);
Are there any better solutions? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我会选择
从 getHandler 返回的经典等待/通知处理程序,然后可以多次使用而无需调用同步 getHandler。
I'd go with the classic wait/notify
Handler returned from getHandler can then be used many times without invoking synchronized getHandler.
准备
Looper
可能会阻塞一段时间,所以我想您遇到了prepare()
需要一段时间才能完成的情况,因此mHandler
> 仍未定义。您可以让您的
Thread
扩展HandlerThread
,但即便如此,您仍然必须等待以确保Looper
已初始化。也许这样的事情可能会起作用,您单独定义了Handler
,但利用了自定义线程的Looper
。或许。
Preparing a
Looper
can block for a while, so I imagine you're hitting a condition whereprepare()
takes a moment to complete, thusmHandler
is still undefined.You could have your
Thread
extendHandlerThread
, though even then you still have to wait to ensure theLooper
has initialised. Perhaps something like this might work, where you have theHandler
defined separately, but utilising theLooper
of your custom thread.Maybe.
我只是想补充一点,检查的答案是最好的答案,但如果你像这样测试它是行不通的,因为你需要在运行方法上调用 super ,因为它负责准备循环器,所以代码应该是这样的:
}
I just want to add that the checked answer is the best one but if you test it like that is not going to work becouse you need to call super on run methode since it's in charge of preparing the looper so the code should be like this:
}