如何在调用之前确保另一个线程的处理程序不为空? [英] How do I ensure another Thread's Handler is not null before calling it?

查看:46
本文介绍了如何在调用之前确保另一个线程的处理程序不为空?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前几天,当我的程序尝试使用在另一个线程上创建的处理程序向该线程发送消息时,它抛出了 NullPointerException.另一个线程创建的 Handler 尚未创建,或者对调用线程不可见,尽管调用线程已经在另一个线程上调用了 start.这种情况很少发生.几乎每次测试运行都不会出现异常.

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.

背景:
在 Android 中,Handler 类可用于将要在与您自己的线程不同的线程上执行的操作排入队列".文档在这里:
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.

当Handler用于UI线程以外的线程时,也必须使用Looper类:
http://developer.android.com/intl/de/reference/android/os/Looper.html

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.

推荐答案

准备 Looper 可能会阻塞一段时间,所以我想您遇到了 prepare() 需要一些时间才能完成,因此 mHandler 仍未定义.

Preparing a Looper can block for a while, so I imagine you're hitting a condition where prepare() takes a moment to complete, thus mHandler is still undefined.

你可以让你的 Thread 扩展 HandlerThread,尽管如此,您仍然需要等待以确保 Looper 已初始化.也许这样的事情可能会奏效,其中您单独定义了 Handler,但使用了自定义线程的 Looper.

You could have your Thread extend HandlerThread, though even then you still have to wait to ensure the Looper has initialised. Perhaps something like this might work, where you have the Handler defined separately, but utilising the Looper of your custom thread.

也许吧.

private void setUp() {
    mHandlerThread = new CustomThread("foo", Process.THREAD_PRIORITY_BACKGROUND);
    mHandlerThread.start();

    // Create our handler; this will block until looper is initialised
    mHandler = new CustomHandler(mHandlerThread.getLooper());
    // mHandler is now ready to use
}

private class CustomThread extends HandlerThread {
    public void run() {
        // ...
    }
}   

private class CustomHandler extends Handler {
    CustomHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        // ...
    }
}

这篇关于如何在调用之前确保另一个线程的处理程序不为空?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆