Android API 31 Handler机制源码解读(一)

Handler机制对于初学者来说,是比较容易发懵的一个机制,但是实际上Handler相关的源码内容相对来说较少,也比较容易理解,对于作为源码旅程的切入点,还是非常合适的。

要讨论Handler这个话题,不可避免要先提到一个问题,什么是Handler?关于什么是Handler,互联网上资料也比较多,老铁们也可以参考阅读。咱们今天看看官方是怎么说的,我们打开android API 31 Handler类的源码,可以看到顶部有如下的注释,

 源码里的注释,值得细读一下,毕竟没有什么比这个更具备说服力了,

A Handler allows you to send and process {@link Message} and Runnable objects associated with a thread's {@link MessageQueue}.

先从Hanlder能干什么说起,Handler能干2件事情,发送(send)和处理(process),能发送和处理2样东西,Message和Runnable,可以发送很多的Message和Runnable,处理需要时间(是异步的),会存在不能及时处理的情况,为了应对这种情况,所以需要用一个队列来管理,就是上面说的MessageQueue(通过后面的分析会了解到,一个线程只能有一个Looper,MessageQueue就在这个Looper里面,所以注释说a thread’s MessageQueue,就是因为存在这层关系)。

Each Handler instance is associated with a single thread and that thread's message queue.

一个Handler只能与一个线程关联,上面已经提到线程里有MessageQueue。

When you create a new Handler it is bound to a {@link Looper}.

创建Handler的时候,会和Looper绑定,Looper和线程是一伙的,所以其实也是和线程绑定的。

It will deliver messages and runnables to that Looper's message queue and execute them on that Looper's thread.

Handler会把Message和Runnable递交给Looper的MessageQueue,然后在Looper所在的线程里进行执行(execute or process)。

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed at some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

Handler有2个主要用途,(1)在未来某个时间点执行一个操作,就是延时操作。(2)在自己的线程,让别的线程来执行一个操作。

读这篇博客的老铁,相信这两个用途已经玩的灰常灰常灰常6了。第1个就是延时执行一个操作,第2个最常见的就是从子线程(非UI线程)来更新UI线程,平时所说主线程和UI线程是等同的。咱通过一个实例作为切入点,实例咱跟平时大部分情况反着来,即从主线程发消息到子线程。Demo code如下,

package com.test.handlerdemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int MSG_TYPE1 = 0, MSG_TYPE2 = 1;
    private Button btn_delay, btn_inter_thread;
    private TextView tv_delay_content, tv_inter_thread_content;
    private Handler threadHandler, uiHandler;
    private Thread thread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_delay = findViewById(R.id.btn_delay);
        btn_inter_thread = findViewById(R.id.btn_inter_thread);
        tv_delay_content = findViewById(R.id.tv_delay_content);
        tv_inter_thread_content = findViewById(R.id.tv_inter_thread_content);
        //创建方法1,方法已经废弃,不推荐使用
        uiHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
            }
        };
        /*
        //创建方法2
        uiHandler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
            }
        };
        //创建方法3
        uiHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
            }
        };
        */
        thread = new Thread(() -> {
            Looper.prepare();
            threadHandler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    Log.i(TAG, "threadHandler handleMessage thread id: " + Thread.currentThread().getId());
                }
            };
            Looper.loop();
        });
        thread.start();
        btn_inter_thread.setOnClickListener(v -> {
            Log.i(TAG, "sendEmptyMessage thread id: " + Thread.currentThread().getId());
            threadHandler.sendEmptyMessage(0);
        });
    }
}

咱先看下Handler的创建,这里声明了2个Handler: threadHandler, uiHandler, 前者用来往子线程发消息,后者用来往主线程发消息。先从uiHandler的创建来说起,这里用了3种方式来创建,第1种是老铁们熟知的,不过Android API 31当中已经标记为不推荐使用。先来看第1种,通过无参的构造方法调用到了this(null, false)即如下的构造:

这里对mLooper和mQueue进行赋值,这里也可以看出,Handler对应的Looper和MessageQueue只有一份,且MessageQueue是包含在Looper当中的。

注意到这段:

        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }

这段代码说,如果mLooper为空,就抛出一个异常:不能在没有调用Looper.prepare()的情况下在xxx线程里创建handler。但是我们实际这样new Handler的时候,并没有去调用Looper.prepare(),但是却没有抛出这个异常,这个是为什么呢,因为有人已经帮咱们调用过Looper.prepare(),就是主线程管理类ActivityThread已经帮咱们prepare过了,在ActivityThread.java的main方法中。先记住创建Handler必须要先Looper.prepare()(只是在UI线程中这一步已经做过,所以可以不用再做)。

第2种和第3种构造,从Handler层面来看没有区别,指定一个Looper,然后去构造,最终调用的是如下的构造方法:

咱们看下Looper.myLooper()和Looper.getMainLooper()有什么区别,我们先来看Looper.getMainLooper():

这里返回了sMainLooper对象,再看看sMainLooper对象是何时赋值的,在Looper类中只有一处赋值,就是prepareMainLooper的时候,

看到这里就很清楚了,在主线程中, getMainLooper()等同于myLooper()。上面提到过,主线程管理类ActivityThread已经帮咱们prepare过了,看过ActivityThread的男人一定知道,在ActivityThread的main方法中,就是调用了这个prepareMainLooper。

好的,能耐心看到这里,相信老铁一定是一个坚挺且持久的男人。总结一下结论:

1. Handler与线程,是多对一的关系,即一个Handler只能属于一个线程,但是一个线程可以有很多Handler。

2. 线程,Looper,MessageQueue,这三者是一一对应的,互相之间均不存在一对多的关系。

3. 在创建Handler之前,要先对Handler所属的线程的Looper进行prepare(其实就是创建Looper对象)。

时间仓促,水平有限,欢迎老铁同行们批评指正,讨论交流,敬请关注后续。

Android API 31 Handler机制源码解读(二)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值