Android消息循环机制-笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zcpvn/article/details/80803694

此文章参考了:http://blog.csdn.net/crazy1235/article/details/51707527

第二张图片取自上面的链接因为是笔记,所以我再自行总结一下

Android不建议在主线程中做耗时操作,比如IO操作、网络请求等操作,否则容易引起程序无法响应(ANR)。Android禁止任何主线程网络连接行为。即使强行为之,Android也会抛出 NetworkOnMainThreadException 异常。所以想这些耗时操作,都会放到其他的线程中进行处理,但是非UI线程又无法操作UI,所以 Handler 就派上用场了。


主线程

线程是个单一执行序列。单个线程中的代码会逐步执行。所有Android应用的运行都是从主线程开始的。然而,主线程不是线程那样的预定执行序列。相反,它处于一个无限循环的运行状态,等着用户或系统触发事件。一旦有事件触发,主线程便执行代码做出响应。事件处理循环让UI代码总是按顺序执行。这样,事件就能一件件处理,不用担心互相冲突,同时代码也能够快速执行,及时响应。

UI Thread 里Looper对象内部维护一个MessageQueue,MessageQueue是消息队列,每个消息可以有共同的Handler处理器或各自拥有一个处理器,Handler处理器负责处理消息和发布消息。


HandlerThread


HandlerThread 类是另一个事件处理循环类,可以通过它来看消息处理的组成部分

可以继承这个类做一些需要用到消息传递的网络连接后台任务

有关于 HandlerThread 类可以前往 https://blog.csdn.net/double2hao/article/details/58598171 查看。


Android异步消息组成介绍

解析异步消息处理机制

Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper。其中Message和Handler在上一小节中我们已经接触过了,而MessageQueue和Looper对于你来说还是全新的概念,下面我就对这4个部分进行一下简要的介绍。

  1. Message

    Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了Message的what字段,除此之外还可以使用arg1arg2字段来携带一些整型数据,使用obj字段携带一个Object对象。

  2. Handler

    Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。

  3. MessageQueue

    MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。

  4. Looper

    Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。

了解了Message、Handler、MessageQueue以及Looper的基本概念后,我们再来把异步消息处理的整个流程梳理一遍。首先需要在主线程当中创建一个Handler对象,并重写handleMessage()方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler的handleMessage()方法中。由于Handler是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线程中运行,于是我们在这里就可以安心地进行UI操作了。整个异步消息处理机制的流程示意图如下图所示。



Handler使用

前面说了,Handler既是Message的处理者也是Message的发布者

先来看看Handler的基本使用。 
它的使用方法分为两套:send 方法和 post 方法。


两个方法都有几个重载,这两个方法的源代码可以去文章开头的参考链接里仔细品味

  • send 方法接受 Message 信息对象并将信息发送出去
  • post  方法接受 Runnable 接口子线程对象并发送出去,post 的这几个方法内部其实都是调用的 send 方法的一些重载,还通过了个内部方法 getPostMessage() 的几个重载方法,将 Runnable 封装成了 Message 

当我们使用 Handler 的时候,通过 post 或者 send 的一些列方法时,实际上是把一个Message(消息)添加到MessageQueue(消息队列)中去。

Looper 可以称之为“消息循环” 然后它从 MessageQueue 中取出 Message 进行处理,Looper 内部的 loop() 方法建立了一个死循环,一直从消息队列中读取消息,然后调用Message的target(目标处理器对象因为Handler既是Message的处理者也是Message的发布者,所以Message的目标处理者一般就是它的发布者),实际上就是Handler对象的 dispatchMessage(msg) 方法进行处理。

dispatchMessage(msg) 的源码如下

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {    // 当message对象中Runnable类型的callback不为空时,即使用post发布的信息
            handleCallback(msg);
        } else {
            ...
            handleMessage(msg);        //调用自定义Handler定义时重写的方法,即使用send发布的信息
        }
    }
    // 调用runnable类型的run()方法
    private static void handleCallback(Message message) {
        message.callback.run();
    }

综上通过dispatchMessage(msg)方法的分发处理,就可以将事件在主线程中处理。


下面是Looper、Handler、MessageQueue 工作原理图图片来源于 zongpeiqing的博客

附上在子线程更新TextView文本的代码

public class MainActivity extends AppCompatActivity {

    private static final int MESSAGE = 0;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE:
                    handleRequest();
                    break;
                default:
                    break;
            }
        }
    };

    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mButton = findViewById(R.id.button_view);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        //obtainMessage()会从公共回收池里获取消息,比创建新实例更加高效.
                        mHandler.obtainMessage(MESSAGE)
                                .sendToTarget();

                        //或者这样
                        //Message message = new Message();
                        //message.what = MESSAGE;
                        //mHandler.sendMessage(message);
                    }
                }.start();
            }
        });
    }

    private void handleRequest() {
        mButton.setText("Nice to meet you!");
    }
}


猜你喜欢

转载自blog.csdn.net/zcpvn/article/details/80803694