美文网首页
Android消息机制

Android消息机制

作者: L_Xian | 来源:发表于2016-05-27 17:29 被阅读21次

    Handler的作用:
    将一个任务切换到 Handler 所在的线程去执行。

    Handler,MessageQueue和Looper的关系:
    MessageQueue 是消息队列,内部存储了一组消息,以队列的形式对外提供插入和删除的工作。采用的是单链表的数据结构来存储消息。
    Looper 是消息循环,因为 MessageQueue 是消息的存储单元,并不能处理消息,所以 Looper 来填补这个功能。Looper 会已无限循环的形式去查找是否有新消息,如果有就处理消息,否则一直等待。

    ThreadLocal:
    ThreadLocal 并不是线程,它的作用是在每个线程中存储并提供数据,并 Handler 内部可以通过它来获得当前线程的 Looper。

    注意:线程默认是没有 Looper 的,要使用 Handler 就要先创建 Looper。
    UI 线程(AcitivityThread)被创建的时候会初始化 Looper,所以在主线程中默认可以使用 Handler。

    延伸:系统为什么不允许在子线程中访问 UI?
    因为 Android 中的 UI 控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。

    Handler的工作原理:
    Handler 通过 Looper 来构建内部的消息循环系统,通过 Handler 的 post 方法将一个 Runnable 投递到 Handler 内部的 Looper 中去处理。
    也可以通过 send 方法发送一个消息。(post 方法其实最终会调用 send 方法)。
    当 send 方法被调用时,它会调用 MessageQueue 的 enqueueMessage 方法将这个消息放入消息队列中,然后 Looper 发现新消息来后,处理消息,最终消息中的 Runnable 或者 Handler 中的 handleMessage 方法会被调用。

    因为 Looper 是运行在创建 Handler 的线程中的,这样 Handler 的业务逻辑就被切换到创建 Handler 所在的线程去执行了。

    ThreadLocal 的工作原理:
    ThreadLocal 是一个线程内部的数据存储类,可以在指定线程中存储数据。数据存储后,只有在指定线程中可以获取到存储的数据,其他线程则无法获取。
    使用场景:当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,或者是复杂逻辑下的对象传递(比如监听器传递),可以考虑采用 ThreadLocal。
    使用例子:

    private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();
    mBooleanThreadLocal.set(true);
    Log.d(TAG,"[Thread#Main]mBooleanThreadLocal = "+mBooleanThreadLocal.get());
    
    new Thread("Thread#1"){
      public void run(){
        mBooleanThreadLocal .set(fasle);
        Log.d(TAG,"[Thread#1]mBooleanThreadLocal = "+mBooleanThreadLocal.get());
      }
    }
    
    new Thread("Thread#2"){
      public void run(){
        Log.d(TAG,"[Thread#2]mBooleanThreadLocal = "+mBooleanThreadLocal.get());
      }
    }
    

    输出结果:

    [Thread#Main]mBooleanThreadLocal = true
    [Thread#1]mBooleanThreadLocal = fasle
    [Thread#2]mBooleanThreadLocal = null
    

    可以看出,虽然在不同线程中访问同一个 ThreadLocal 对象,但是他们通过 ThreadLocal 获取到的值却是不一样。这就是 ThreadLocal 的奇妙之处。

    消息队列的工作原理:
    MessageQueue 主要包含两个操作:插入和读取。读取本身会伴随着删除操作。

    插入对应的方法是 enqueueMessage(往消息队列中插入一条消息)
    读取对应的方法是 next(从消息队列中取出一条消息并将其从消息队列中删除)

    next 是一个无限循环的方法,如果消息队列中没有消息,那么 next 方法就会一直阻塞,当有新消息到来时,next 方法会返回这条消息并将其从单链表中移除。

    Looper的工作原理:
    如何创建一个 Loopre :通过 Looper.prepare() 即为当前线程创建一个 Looper,接着通过 Looper.loop() 来开启消息循环。

    new Thread("Thread#1"){
      public void run(){
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
      }
    }.statrt();
    
    1. Looper 提供了 prepareMainLooper 方法为主线程(ActivityThread)创建 Looper(本质也是通过 prepare 方法实现)
    2. Looper 提供了 getMainLooper 方法,可以在任何地方获取到主线程的 Looper.
    3. Looper 提供了 quit和quitSafely 方法来退出一个 Looper,两者区别是 quit 是直接退出,quitSafely 只是设定一个退出标记,然后把消息队列中已有消息处理完毕后才安全退出。

    Handler的工作原理:
    Handler 发送消息的过程仅仅是向消息队列中插入一条消息,MessageQueue 的 next 方法就会返回这条消息给 Looper,Looper 接收到消息后就开始处理了,最终消息由 Looper交由 Handler 处理,即 Handler 的 dispatchMessage 方法会被调用,这时 Handler 就进入了消息处理阶段。

    相关文章

      网友评论

          本文标题:Android消息机制

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