美文网首页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