美文网首页Android技术知识Android开发
Handler为什么可以实现线程间通讯?

Handler为什么可以实现线程间通讯?

作者: 猫叔很不爽 | 来源:发表于2020-03-12 11:21 被阅读0次

    天空灰的他妈的像哭过。

    从前经常听到大佬们说,Android是一个消息驱动型系统,一直都不懂是什么意思。搞了五年Android,还是个垃圾开发崽,问啥啥不会,再问就CV。每次面试都看一遍Handler,看了这么多次,也是一知半解,总觉得好像会,又好像不会,真的是菜得像狗一样。事实证明,搞IT,还真是要认真动脑子的,不动脑子,就会永远停留在会用的层面上。最终成为我这样,一个CV程序猿,API程序猿,垃圾开发崽。
    哎,好好学习下吧。

    为什么说Android是一个消息驱动型系统呢?

    最近看了很多Android FrameWork的知识,什么AMS,PMS,WMS,SystemServer等等。发现Binder机制用的最多。比如说,我要启动一个新的Activity,就要通过Binder配合AMS发送一个消息,最终配合Handler创建启动这个Activity。同样的,启动Service,发送广播。都是这个大致流程。
    用户启动Activity消息-------AMS发送消息给,系统检查要启动的Activity进程是否存在---------检查完毕发送Handler消息创建Activity并启动
    也就是说,一个动作驱动下一个动作,下一个动作又驱动下下一个动作,最终返回我们想要的结果。
    这大概就是消息驱动型系统吧。

    FrameWork说多了我也不会,还是搞Handler吧。

    首先看一个Handler初始化的方法

    public Handler(@Nullable Callback callback, boolean async) {
            .....
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    

    可以看到初始化方法里面搞了一个Looper,通过Looper又搞了一个mQueue。看一下myLooper()方法

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

    sThreadLocal是一个线程存储数据的类。通过这个数据类获取到了一个Looper对象,并返回给了Handler。
    由于我们的Handler是在主线程创建的,所以sThreadLocal存储的是主线程中的looper对象。

    public static void main(String[] args) {
        ..........
            Looper.prepareMainLooper();
        ..........
             ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    

    上面这东西就是我们平常所说的主线程,我们的程序都是运行在这个Looper里面,Looper不停的从MessageQueue中拿出消息,处理消息,这也证明了我们Android确实是消息驱动型系统。
    可以看到在main()方法中调用了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();
            }
        }
    
     public static void prepare() {
            prepare(true);
        }
    
        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));
        }
    
    public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    从这里看到在这里创建了Looper对象,并且存到了主线程的sThreadLocal中。这样在前面通过sThreadLocal.get()就得到了一个主线程的Looper了
    Looper.loop()就是从消息队列中不停的拿出消息,然后分发处理。
    最后再来看一下Handler发送消息的过程。

    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    

    拿到Handler对应的消息队列,并将新消息加入到消息队列中。
    到这里我的分析就完了。

    如题,为什么Handler可以实现线程间通讯呢?

    从上面的分析可以看到,当我们在子线程中使用handler.sendMessage()的时候,由于这个子线程中的这个handler是在主线程创建的,处理这个消息的Looper,MessageQueue也都是在主线程中创建的。消息一发送,就立马把消息发送到主线程中的这个MessageQueue中去了,然后被Looper调用消息,分发回调给我们的主线程handleMessage()方法。也就是说,这个消息的发送处理,和子线程完全没有关系。

    其实,屌大的大佬们已经把Handler的祖宗十八代都分析了好几遍。我这个菜鸡分析只是记录下自己一直迷惑的地方。
    想通了这个问题,再回头看看Handler,发现它也不过如此。我甚至能手写一个Handler,嘿嘿,下篇手写一下Android系统。哦,不对,是手写下Handler。

    相关文章

      网友评论

        本文标题:Handler为什么可以实现线程间通讯?

        本文链接:https://www.haomeiwen.com/subject/efkyjhtx.html