您当前的位置: 首页 >  android

Kevin-Dev

暂无认证

  • 3浏览

    0关注

    544博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Android -- 多线程】Handler 消息机制

Kevin-Dev 发布时间:2017-03-13 09:37:39 ,浏览量:3

在这里插入图片描述

文章目录
    • 一、简介
    • 二、消息机制的模型
    • 三、消息机制的架构
    • 四、消息机制的源码解析
      • 1.Looper
      • 2.Handler
      • 3. 发送消息
      • 4. 获取消息
      • 5. 分发消息

提起 Android 消息机制,想必都不陌生。其中包含三个部分:Handler,MessageQueue 以及 Looper,三者共同协作,完成消息机制的运行。

一、简介

在 Android 中使用消息机制,我们首先想到的就是 Handler 。没错,Handler 是 Android 消息机制的上层接口。Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到 Handler 所在的线程中去执行。通常情况下,Handler 的使用场景就是更新 UI 。

public class TestActivity extends AppCompatActivity {
    private static final String TAG = "TestActivity";
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Log.d(TAG, msg.what + "");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = Message.obtain();
                message.what = 1;
                mHandler.sendMessage(message);
            }
        }).start();
        
    }
}

在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新 UI。这便是消息机制的典型应用场景。我们通常只会接触到 Handler 和 Message 来完成消息机制,其实内部还有两大助手来共同完成消息传递。

二、消息机制的模型
  • 消息(Message) 需要传递的消息,可以传递数据;

  • 消息队列(Message Queue) 消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);

  • 处理者(Handler) 消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage)

  • 循环器(Looper) 不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

三、消息机制的架构

消息机制的运行流程:在子线程执行完耗时操作,当 Handler 发送消息时,将会调用MessageQueue.enqueueMessage,向消息队列中添加消息。当通过Looper.loop开启循环后,会不断地从线程池中读取消息,即调用MessageQueue.next,然后调用目标Handler(即发送该消息的Handler)的dispatchMessage方法传递消息,然后返回到Handler所在线程,目标Handler收到消息,调用handleMessage方法,接收消息,处理消息。 在这里插入图片描述 MessageQueue,Handler 和 Looper 三者之间的关系:每个线程中只能存在一个 Looper,Looper是保存在 ThreadLocal 中的。主线程(UI线程)已经创建了一个 Looper ,所以在主线程中不需要再创建 Looper ,但是在其他线程中需要创建 Looper 。每个线程中可以有多个 Handler ,即一个 Looper 可以处理来自多个 Handler 的消息。 Looper 中维护一个 MessageQueue ,来维护消息队列,消息队列中的 Message 可以来自不同的 Handler 。 在这里插入图片描述

下面是消息机制的整体架构图 在这里插入图片描述

四、消息机制的源码解析 1.Looper

要想使用消息机制,首先要创建一个 Looper。 初始化 Looper 无参情况下,默认调用 prepare(true) ;表示的是这个Looper可以退出,而对于false的情况则表示当前Looper不可以退出。

 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));
    }

这里看出,不能重复创建 Looper,只能创建一个。创建 Looper,并保存在 ThreadLocal 。其中 ThreadLocal 是线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的 TLS 区域。

开启 Looper

public static void loop() {
    final Looper me = myLooper();  //获取TLS存储的Looper对象 
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;  //获取Looper对象中的消息队列

    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) { //进入loop的主循环方法
        Message msg = queue.next(); //可能会阻塞,因为next()方法可能会无限循环
        if (msg == null) { //消息为空,则退出循环
            return;
        }

        Printer logging = me.mLogging;  //默认为null,可通过setMessageLogging()方法来指定输出,用于debug功能
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        msg.target.dispatchMessage(msg); //获取msg的目标Handler,然后用于分发Message 
        if (logging != null) {
            logging.println("            
关注
打赏
1658837700
查看更多评论
0.0464s