Handler,looper,MessageQueue及 handlerThread 之间的关联和用法

Handler 是什么?这个是android面试官最喜欢问的问题,用脚趾都能回答出来,Handler可用于android多线程通信,可以用来更新UI的,用来发送message,处理message的。于是在很多地方我们都直接new 一个Handler 来使用,那么问题来了,如果你在一个自定义线程中new一个Handler,这个Handler能用么?能 or 不能。 Why?

先给大家上个图,好有个整的印象:


呵呵,现在老鸟带你揭开Handler这个神秘的面纱,大家都知道Handler 是用来发送和处理message的,那么message存在哪里呢?答案是MessageQueue,  Handler发送的message当然要放在MessageQueue了,那么问题又来了,MessageQueue中的message谁在管理,是Handler?  NO, NO, 是Looper。 下面我们看看Handler的部分源码:

 public Handler() {
        this(null, false);
 }
 public Handler(Callback callback, boolean async) {
        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;
    }

看到这里是不是豁然开朗了,Handler需要一个Looper, Looper里面有一个mQueue, 这个mQueue就是MessageQueue,不信?你去看Looper.java源码。所以自定义线程中是不能就这么简单的new一个Handler来用滴。如果没有这个Looper,在运行时是会抛出异常滴。那么问题又来了,为啥我们在Activity或Fragment里面可以直接new一个Handler来用呢?答案是:因为应用的主线程帮我们定义好了这个Looper,我们在Activity或Fragment里面new一个Handler都是使用主线程的Looper。 

呵呵,说到主线程,是不是又让人蒙啦,大名鼎鼎的android主线程,就是UI线程,老鸟在这里给你简单介绍下吧,更详细的关于主线程,老鸟会单独N篇文章讲解。首先,主线程就是ActivityThread, 每一个应用有且只有一个主线程,UI改变都是在这个AcitivityThread里面完成的。在这里我们只关心ActivityThread是如何创建主线程Looper的,下面是ActivityThread部分源码:

 public static void main(String[] args) {
      
        Environment.initForCurrentUser();

    
        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

ActivityThread的main方法里会调用Looper.prepareMainLooper方法,这个方法就是创建主线程的Looper, 并且后面执行了Looper.loop(),这个loop()就是一个for(;;)永久循环,这个循环体里面就是不断判断是否有新的message进入了Looper的MessageQueue里面,如果有message,就把他发送给发送这个message的handler去执行。当我们在activity或fragment里面new一个Handler的时候,其实都是拿到主线程这个Looper,然后发消息到这个Looper的MessageQueue里。那么我们在activity里面是怎么拿到这个主线程Looper的呢?在上面的Handler代码里我们new一个Handler的时候,会调用Looper.myLooper(),下面看看Looper的部分代码:

 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
 }  

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
 }

 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
 }

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
}

由上面代码可以知道prepareMainLooper调用了prepare(), prepare()里面执行了new Looper(), 这里新建了一个MessageQueue, 最后并且把这个looper存入了sThreadLocale里面。所以当我们在activity或fragment里面new Handler的时候,都会从myLooper()里面拿到这个主线程looper啦。

那么又有问题来了,我们自己定义的thread里面我也想用Handler怎么办?这个问题现在是不是很简单了?就是我们自己也给我们的线程生成一个Looper,不就OK了么,对滴,就这样。上面调用Looper的prepare()就会为我们生成一个Looper。如何把这个looper跟我们的Handler关联起来呢,我们可以用调用Handler(Looper looper)这样,把他们关联起来,最后调用Looper.loop()让这个looper动起来,这样你就可以用这个Handler发送处理message啦。是不是很爽。

 class MyLooperThread extends Thread{
        private final String TAG = "MyLooperThread";
        private MyHandler mHandler;
        public MyLooperThread(){       
        }
        @Override
        public void run() {
            super.run();    
            Looper.prepare();
            mHandler = new MyHandler(Looper.myLooper());
            Looper.loop();
        }

        public void sendMessage(Message msg){
            mHandler.sendMessage(msg);
        }
        class MyHandler extends Handler{
            MyHandler(Looper looper){
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what){
                    case 1:             
                        Log.i(TAG,"1111111111111");
                        break;
                    default:
                }
            }
        }
    }

上面我们就可以在handleMessage里面处理我们自己的消息啦。

说了这么多我们还没说HandlerThread, 这个又是什么鬼呢?其实这个就是android帮我们封装了Looper的一个thread,它的实现就跟我们上面自己的MyLooperThread差不多,使用它我们就不用自己去手动调用生成Looper的代码啦,这是不是很贴心呢。


更多精彩Android技术可以关注我们的微信公众号,扫一扫下方的二维码或搜索关注公共号:  Android老鸟

                                                





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值