美文网首页
Handler机制,四个组成部分及源码解析

Handler机制,四个组成部分及源码解析

作者: PeterHe888 | 来源:发表于2018-05-14 18:06 被阅读30次

    Android的消息机制主要指的是Handler的消息机制。其主要由Message、MessageQueue、Looper、Handler组成。

    1. ThreadLocal
      理解ThreadLocal对于理解Handler的消息机制有很大的帮助。它是线程内部的一个数据存储类。

    使用场景:
    1.某些数据是以线程为作用域且不同线程具有不同数据副本的时候(Looper)
    2.使用场景是复杂逻辑下对象传递
    ThreadLoca的使用:

    final ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<>();
            mThreadLocal.set(true);//UI Thread
            Log.i(TAG, "[mainThread]mThreadLocal="+mThreadLocal.get());
    
            new Thread("Thread#1") {
                @Override
                public void run() {
                    mThreadLocal.set(true);
                    Log.i(TAG, "[Thread#1]mThreadLocal="+mThreadLocal.get());
    
                }
            }.start();
    
            new Thread("Thread#2") {
                @Override
                public void run() {
                    Log.i(TAG, "[Thread#2]mThreadLocal="+mThreadLocal.get());
                }
            }.start();
    

    2.消息队列的工作原理

    MessageQueue只要包括俩个操作,插入和读取消息,enqueue()、next()。内部是通过单链表实现的。调用enqueue()方法实现消息的插入,next()方法返回一条消息,并从消息队列移除该消息。next 方法是一个无限循环的方法,如果消息队列中没有消息的话,next方法会一直阻塞在这里。当有消息时,将其从单列表总移除。

    3.Looper的工作原理

    Looper在Android的消息机制中扮演着消息循环的角色,在它的构造方法中会创建一个MessageQueue,然后将当前线程保存起来。
    通过Looper.prepare()创建一个Looper,Looper.loop开启消息循环。当任务处理完成后,应调用Looper.quit/quitSafely退出循环。二者的却别是quit会直接退出Looper,后者会把消息队列中的已有消息处理完毕后安全的退出。如果不退出,则该线程就会一直处于等待状态,当Looper退出后,该线程就会立刻停止。
    loop方法是一个死循环,只有当next方法返回null时,才会退出循环。当调用Looper.quit方法时,会调用MessageQueue的quit/quitSafely方法来通知消息队列退出,则此时next方法会返回null。loop会调用MessageQueue的next获取新消息,next方法是一个阻塞操作,当没有消息时,next方法会一直阻塞在哪里,这也导致loop方法一直阻塞在那里。最终会调用msg.target.dispatchMesage方法处理消息。Handler的dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就把代码逻辑切换到指定的线程中去执行了。

    4.Handler的工作原理

    Handler通过post或send方法发送消息,其调用过程是sendMessage->sendMessageDelayed->sendMessageAtTime,在sendMessageAtTime方法中会调用MessageQueue的enqueue方法将消息加入到消息队列中。MessageQueue的next方法就会被调用,Looper收到消息后就会处理,最终消息交由Handler去处理,即Handler的dispatchMessage方法会被调用。
    这里涉及到一个使用Handler的方式:
    1.派生Handler的一个子类并重写其handleMessage方法
    2.通过实现CallBack接口,达到直接使用Handler,不需要派生子类
    3.通过Looper构造Handler一个Handler,实现一些特殊的功能。

    5.主线程的消息循环

    ActivityThread的入口方法为main方法,通过Looper.prepareMainLooper()来创建。ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间的通信方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程中执行。

    6.为什么Android中子线程不能访问UI控件?

    因为Android的主线程不是线程安全的,多线程并发访问可能会导致UI控件出现不可预期的结果,那为什么不对UI控件加入同步锁机制呢?
    大致原因有二:

    • 加入锁机制会使逻辑复杂
    • 锁机制会降低UI访问效率,同步锁会阻塞某些线程的执行
      所以Android主线程使用单线程模型来执行UI操作。

    7.子线程有哪儿些更新UI的方法?

    • 通过在主线程创建Handler,子线程发送消息,Handler接受并处理子线程发来的消息
    • 用Activity.runOnUiThread方法
    • 创建Handler,传入getMainLooper
    • view.post(Runnable r)

    8.解决Handler内存泄露的方法?
    使用Handler为什么会造成内存泄露?

    • 有延时消息时,改消息会一直保存在主线程的消息队列里,并且影响系统对Activity的回收,当Activity销毁时要移除延时消息
    • 匿名内部类导致的内存泄露,使用静态内部类,并且对上下文或Activity使用弱引用。

    相关文章

      网友评论

          本文标题:Handler机制,四个组成部分及源码解析

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