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

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

问题描述

我的程序抛出一个NullPointerException异常有一天,当它试图用另一个线程创建的处理程序来发送线程的消息。由其他线程创建的处理程序还没有建立,或没有可见的调用线程,尽管有其他线程已经调用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.

我在想,最好的办法就是避免这个问题肯定以最小的复杂性和性能损失。该方案是一个游戏,十分性能敏感的,特别是当它正在运行。因此,我尽量避免使用同步设置后,例如,并且将preFER,以避免在任何时候纺纱上的变量。

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中的处理程序类可用于排队要在不同的线程比你自己执行的操作。文档在这里:
<一href="http://developer.android.com/intl/de/reference/android/os/Handler.html">http://developer.android.com/intl/de/reference/android/os/Handler.html

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

,此Handler必须在那里将使用的线程上创建的。因此,在一个线程,这是通过创建线程的线程中运行的构造创建它,是不是一个选项。

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.

在处理程序是一个线程比UI线程等,弯针类也必须使用:
<一href="http://developer.android.com/intl/de/reference/android/os/Looper.html">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.
            }        
        }
    }

}

随着code在创建线程看起来像这样:

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.

推荐答案

preparing一个尺蠖可一会儿块,所以我想你打一个条件,其中 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.

您可以有你的扩展的 HandlerThread ,但即使如此,你还是要等,保证了尺蠖已初始化。或许,这样的事情可能会奏效,在那里你有处理程序单独定义的,但使用自定义线程的尺蠖

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天全站免登陆