子线程是否可以创建Handler

很多时候在项目中我们会用到一些独立的类,用来处理通用的逻辑,也有可能会牵扯到切换到UI线程进行比如Toast提示,不经意间会在当前类中new Handler,比如像下面这个, 假设A是一个单例模式,在整个应用生命周期都存在着:

public class A {

    private static A sInstance;

    Handler mHandler = new Handler();

    private A(){}
    
    public static A getsInstance() {
        if (sInstance == null) {
            synchronized (A.class) {
                if (sInstance == null) {
                    sInstance = new A();
                }
            }
        }
        return sInstance;
    }
    
}


 这段代码看上去没有什么特别,如果A这个类在主线程进行实例化是不会有什么问题,但如果在一个子线程进行实例化就会报错提示Can't create handler inside thread that has not called Looper.prepare() 说的是不能在主线程来创建Handler,咱们根据这个异常提示看一下Handler源码 
  

public class Handler {

   /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }
	
	/**
     * Constructor associates this handler with the {@link Looper} for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     *
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Callback callback) {
        this(callback, false);
    }


    /**
     * Use the provided {@link Looper} instead of the default one.
     *
     * @param looper The looper, must not be null.
     */
    public Handler(Looper looper) {
        this(looper, null, false);
    }


    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }


    /**
     * Use the {@link Looper} for the current thread
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with represent to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(boolean async) {
        this(null, async);
    }
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

}
我们可以清楚地看到,它有几个构造方法,最终的调用会到一起,问题就出现在if (mLooper == null)之处,由于我们在子线程来构造Handler实例,所以Looper.myLooper()返回为空,如果在主线程,那么返回的则Looper.myLooper()不会为空,那么我们有没有其它办法可以使得我们Handler实例化时不会报错呢,通过刚才的几个构造方法中我们已经查觉到有一种构造方法是接收Looper参数,那么我们能不能给它传入一个Looper对象呢,答案是可以的,如果查阅Looper的API会发现它可以返回主线程的Looper对象Looper.getMainLooper(), 接下来我们这么改动

public class A {
        
        Handler mHandler = new Handler(Looper.getMainLooper());
    }

public class LogoActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread() {
            
            public void run() {
                A a = new A();
            }
        }.start();
    }
}

这样就不会再报错了,当然还有其它方式来初始化这个Handler,需要读者自己去看

你可能感兴趣的:(子线程是否可以创建Handler)