Android点将台:烽火狼烟[-Handler-]

我的全部文章整理在此篇,将陆续更新收录:知无涯,行者之路莫言终(个人编程之路)java

前言

哥发誓,这是我最后一次分析Handler(这是我第三次说这句话,但愿不会有下次了)
提及Handler新手的小噩梦,用起来不难,理解起来烦神android

Handler总览

Handler.png


1、引入Handler的通常套路

1.说Handler通常套路是从一个异常开始

你觉得我会这么俗气地从:非主线程禁止更新UI开始说Handler吗?--是的
这个异常定义在ViewRootImpl里,更新TextView的UI为何ViewRootImpl报异常?
子不教,父之过,教不严,师之惰呗。在framework的源码里看一下吧,编程

非主线程禁止更新UI.png

---->[ViewRootImpl#checkThread]-------
void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}
|--可见在checkThread时会判断mThread是否是等于当前线程,若是不等于,就异常
|---那mThread又是什么线程呢?

---->[ViewRootImpl#ViewRootImpl]-------
public ViewRootImpl(Context context, Display display) {
    mThread = Thread.currentThread();
|--在构造方法中被赋值的,也就是说是建立ViewRootImpl时所在的线程
|---ViewRootImpl又是在哪里被建立的呢?这里不深刻讲了,是在main线程
|---从异常来看是在进行requestLayout方法时崩的

---->[ViewRootImpl#requestLayout]-------
@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}
复制代码

2.而后再俗套的说一下怎么用Handler解决

而后发现Handler好神奇啊,至于那里神奇也说不出个道道,也就是神秘
Handler的面具之下隐藏着一个有点小复杂的消息机制,这篇就来理一下bash

public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            msgTv.setText("hello");
        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v->{
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(0x01);
                }
            }).start();
        });
    }
}
复制代码

3.源码中对Handler的描述

本身翻译的,仅供参考,有不恰之处敬请指出
其中提到了MessageQueuemessage以及runnables异步

|--Handler容许您发送和处理与线程的MessageQueue关联的消息和可运行对象。
|--每一个Handler实例都与单个线程和该线程的消息队列相关联。
|--当您建立一个新的Handler时,它会被绑定到正在建立它的线程的线程/消息队列上,
|--从那时起,它将向该消息队列传递消息和可运行项,并在它们从消息队列发出时执行它们。

|--Handler有两大主要的用处:
|--(1) 安排将消息和可运行项在未来的某个点执行
|--(2) 将在不一样线程上执行的操做加入队列。

|--调度消息是经过方法:
|--post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long),
|--sendEmptyMessage(int), sendMessage(Message),sendMessageAtTime(Message, long),
|--sendMessageDelayed(Message, long). 
复制代码

4.主要成员变量

Handler主要成员变量.png

final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
复制代码

5.构造方法

看这七个葫芦娃,核心就只有两个构造方法(三个hide的,外面不能用),其余四个能够用async

Handler的七个构造函数.png

|--对具备指定回调接口的[当前线程]使用Looper,并设置handler是否应该是异步的。
|--默认状况下,handler是同步的,除非使用此构造函数建立一个严格异步的handler。
|--(插句话,此方法是隐藏的,说明外部调用者是没法建立异步的handler)

|--异步消息表示:不须要对同步消息进行全局排序的中断或事件。
|--异步消息不受MessageQueue#enqueueSyncBarrier(long)引入的同步屏障的限制。

* @param callback 处理消息的回调接口,或null。
* @param async 若是为true,handler将为[发送到它那的每一个Message或Runnable]调用
* Message#setAsynchronous(boolean)
---->[Handler#Handler(Callback,boolean)]-------------------------------
public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {//final常量---false,因此无论他  
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    mLooper = Looper.myLooper();//经过Looper的myLooper方法返回值,为mLooper赋值
    if (mLooper == null) {//若是mLooper拿不到,报异常
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;//mQueue经过mLooper获取
    mCallback = callback;//入参
    mAsynchronous = async;//入参
}
|--貌似也没有作什么东西,只是将mLooper、mQueue、mCallback、mAsynchronous赋值
|--焦点在Looper.myLooper()上

---->[Handler#Handler(Callback,boolean)]-------------------------------
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
|--三参的大佬挺任性,直接赋值,因此Handler的构造函数没有什么太特别的
|--下面看一下Looper类
复制代码

2、赤胆忠心:Looper

1:ThreadLocal

花了点时间看了ThreadLocal,已单独成文,详情见:java点将台:多重影分身[-ThreadLocal-]
这里不过多探讨ThreadLocal,给个小例子,看它的功能ide

public class ThreadLocalTest {
    //实例化一个装载Integer类型的ThreadLocal静态变量
    static final ThreadLocal<Integer> sThreadLocal = new ThreadLocal<>();
    //用来测试的共享成员变量
    static int count = 10;
    public static void main(String[] args) throws InterruptedException {
        sThreadLocal.set(count);
        Thread thread = new Thread() {
            @Override
            public void run() {//新建线程
                count++;
                sThreadLocal.set(count);
                System.out.println("new :" + sThreadLocal.get());
            }
        };
        thread.start();
        thread.join();//为避免歧义,这里新线程join,让main线程的打印在新线程执行以后
        System.out.println("main:"+sThreadLocal.get());

    }
}
复制代码

结果2.png

能够看出,在新线程中对sThreadLocal.set(),并不会影响main线程的get()
因此共享成员变量count放在sThreadLocal这个篮子里,能够保证线程间共享变量的独立函数

ThreadLocal基本使用2.png


2.Looper类(looper:/'luːpə/ 循环者)
类名:Looper      父类:Object      修饰:public final
实现的接口:[]
包名:android.os   依赖类个数:7
内部类/接口个数:0
源码行数:344       源码行数(除注释):158
属性个数:8       方法个数:20       public方法个数:18
复制代码

Looper构造函数+主要成员变量.png

---->[Looper#成员变量]------------
//实例化一个装载Looper类型的ThreadLocal静态变量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//似有静态内部成员变量sMainLooper
private static Looper sMainLooper; 
//MessageQueue对象
final MessageQueue mQueue;
//线程对象
final Thread mThread;

---->[Looper#Looper]------------
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
|--在Looper的构造函数中,分别对mQueue,mThread进行初始化
|--注意构造函数是私有的,因此没法直接构造Looper对象

复制代码

因此本类中必定存在new Looper,搜索一下:oop

搜索.png

//公共静态方法:准备
---->[Looper#prepare]------------
public static void prepare() {
    prepare(true);
}

//私有静态方法:准备
---->[Looper#prepare(boolean)]------------
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
    //若是sThreadLocal可与获取到Looper,抛异常
    //也就是一个线程只可以建立一个Looper
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //为空时建立Looper对象,并以sThreadLocal为键,new Looper(quitAllowed)为值
    //设置到当前线程的threadLocals(ThreadLocalMap对象)上
    sThreadLocal.set(new Looper(quitAllowed));
}

---->[Looper#prepare(boolean)]------------
 public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
}
|--Looper会在因ThreadLocal在每一个线程中独立,非Looper生成的线程
|--sThreadLocal.get()会获得null,那prepare()是framework层的那里初始化(即prepare)的呢?
复制代码

3.ActivityThread中对Looper的初始化

到framework层的源码去看一下,程序的入口main方法在ActivityThread中post

ActivityThread中关于Looper.png

---->[ActivityThread#成员变量]---------
final Looper mLooper = Looper.myLooper();

---->[ActivityThread#main]---------
public static void main(String[] args) {
    //略...
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();//开启loop
    throw new RuntimeException("Main thread loop unexpectedly exited");
    
---->[Looper#prepareMainLooper]---------
public static void prepareMainLooper() {
    //这里调用了prepare方法,为sThreadLocal设置了Looper值
    并且在main函数中调用,所在线程为main线程,即主线程
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {//这里看出只能prepared一次
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();//在这里初始化成员变量sMainLooper
    }
}
复制代码

在这里为了方便说明,debug来测试一下:
在main线程和子线程分别进行断点调试,看一下两个线程中的Looper.myLooper()
因为Looper.prepare在main线程中执行,即:sThreadLocal.set在main线程
因此Looper.myLooper(),即sThreadLocal.get()在子线程没法获取到Looper,这就是ThreadLocal的做用

Looper.myLooper()测试.png


3、再看Handler

1.使用含Callback的构造函数

之前是直接在Handler中覆写handleMessage方法,AndroidStudio飘橙色,看起来很碍眼
咱们彻底能够传回调来构建Handler,加上Java8的简化书写看着爽多了,运行无误

public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler ;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler(msg -> {
            msgTv.setText("hello");
            return true;
        });
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v->{
            Thread thread = new Thread(() ->
                    mHandler.sendEmptyMessage(0x01));
            thread.start();
        });
    }
}
复制代码

2.看一下CallBack接口
/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
  在实例化处理程序时可使用回调接口,以免必须实现本身的处理Handler子类。
 */
  ---->[Handler$Callback]----------------------
public interface Callback {
    /**
     * @param msg A {@link android.os.Message Message} object
     * @return True 若是不须要进一步处理
     */
    public boolean handleMessage(Message msg);
}


/**
 * Handle system messages here.(在这里处理系统消息)
 */
 ---->[Handler#dispatchMessage]----------------------
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {//若是mCallback不为空
        //先回调用 mCallback.handleMessage(msg),返回true的话,以后就return了  
        //这有什么用? 若是你重写Handler的handleMessage又有Callback都有的话
        // true就不会再去执行Handler的handleMessage 的方法了,例子以下
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
复制代码

3.即便用Callback又覆写handleMessage

感受很不是很经常使用,了解一下便可,
下面代码return true;结果是hello,return false;结果是hello2

public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler(msg -> {
            msgTv.setText("hello");
            return true;
        }) {
            @Override
            public void handleMessage(Message msg) {
                msgTv.setText("hello2");
            }
        };
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {
                mHandler.sendEmptyMessage(0x01);
            });
            thread.start();
        });
    }
}
复制代码

4.在子线程中建立Handler对象是否有用?

如今将建立Handler放在子线程进行,不出所料,崩了

子线程中初始化Handler.png

public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler.Callback callback = msg -> {
            msgTv.setText("hello");
            return true;
        };
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {
                mHandler = new Handler(callback);//<--建立Handler
                mHandler.sendEmptyMessage(0x01);
            });
            thread.start();
        });
    }
}

---->[看一下崩的缘由]----------------
---->[Handler#Handler(Callback, boolean)]----------------
public Handler(Callback callback, boolean async) {
    //略...
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
|---前面咱们已经debug过,在子线程中Looper.myLooper()为空,因此会崩掉
复制代码

5.如何在子线程中建立Handler

Handler的构造函数中有Looper参数,咱们能够在外面获取主线程的Looper对象,给Handler构造
除此以外Context也给咱们提供了获取main线程Looper的方法,debug能够看出,二者是同一对象

如何在子线程中建立Handler.png

public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler.Callback callback = msg -> {
            msgTv.setText("hello");
            return true;
        };
        Looper looper = Looper.myLooper();//获取main线程的looper
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {
                mHandler = new Handler(looper,callback);
                mHandler.sendEmptyMessage(0x01);
            });
            thread.start();
        });
    }
}
复制代码

4、消息队列(难点,核心)

1.回到这个最简单的消息发送
public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Handler.Callback callback = msg -> {
            msgTv.setText("hello");
            return true;
        };
        mHandler = new Handler(callback);

        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);

        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {
                mHandler.sendEmptyMessage(0x01);
            });
            thread.start();
        });
    }
}
复制代码

2.走一下Handler源码

一连串的sendMessageXXX基本上把发送消息的方法走了一遍,
但万剑归一,最终调用的是enqueueMessage(MessageQueue queue,Message msg, long uptimeMillis)

sendEmptyMessage(int what) : 发送空消息,
sendEmptyMessageDelayed(int what, long delayMillis),发送延迟空消息
sendMessageDelayed(Message msg, long delayMillis) 发送延迟消息
sendMessageAtTime(Message msg, long uptimeMillis) 定时发送消息
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 消息入队
复制代码

Handler发送消息.png

---->[Handler#sendEmptyMessage]-----------------
|--只有消息的what(用来表识消息),调用:sendEmptyMessageDelayed
public final boolean sendEmptyMessage(int what){
    return sendEmptyMessageDelayed(what, 0);
}

---->[Handler#sendEmptyMessageDelayed]-----------------
|--只有消息的what(用来表识消息),延迟毫秒数,调用:sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

---->[Handler#sendMessageDelayed]-----------------
|--接收一个消息对象,延迟毫秒数,调用 sendMessageAtTime
public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

---->[Handler#sendMessageAtTime]-----------------
|--接收一个消息对象,延迟毫秒数,调用 enqueueMessage
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;//获取消息队列
    if (queue == null) {//消息队列为空,抛异常
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

---->[Handler#enqueueMessage]-----------------
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//注意这里讲当前Handler做为消息的target
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);//调用了MessageQueue的enqueueMessage方法
}
复制代码

如今咱们面前出现了两个类:MessageMessageQueue


3.先看Message(消息)类

Message的成员变量有点多

what----int 型,用来表识该信息
arg1----int型,储存简单的int数据
arg2----int型,储存简单的int数据
obj --- 任意类型,储存任意数据
replyTo ---- Messenger类型 可选的信使,在那里回复这条消息能够发送。具体如何使用它的语义取决于发送方和接收方。
复制代码

Message部分红员变量.png

先从一个例子开始引入Message吧


3.1:new Message()Message.obtain()Handler.obtain()

可见三种方式都能运做,那么有什么区别呢?

三种建立消息对象的方式.png

/**
 * 做者:张风捷特烈<br/>
 * 时间:2019/1/25/025:14:24<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:三种建立消息对象的方式
 */
public class HandlerActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler.Callback callback = msg -> {
            String txt = (String) msg.obj;
            switch (msg.what) {
                case 0x01:
                    txt += "----第一条";
                    break;
                case 0x02:
                    txt += "----第二条";
                    break;
                case 0x03:
                    txt += "----第三条";
                    break;
            }
            msgTv.setText(txt);
            return true;
        };
        mHandler = new Handler(callback);
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {
                //new Message()建立消息
                Message newMsg = new Message();
                newMsg.what = 0x01;
                newMsg.obj = "玉面奕星龙";
                mHandler.sendMessage(newMsg);
                //Message.obtain()建立消息
                Message msgObtain = Message.obtain();
                msgObtain.what = 0x02;
                msgObtain.obj = "张风捷特烈";
                mHandler.sendMessageDelayed(msgObtain, 3000);
                //mHandler.obtainMessage()建立消息
                Message handlerObtain = mHandler.obtainMessage();
                handlerObtain.what = 0x03;
                handlerObtain.obj = "千里巫缨";
                mHandler.sendMessageDelayed(handlerObtain, 6000);
            });
            thread.start();
        });
    }
}
复制代码

3.2:三者的区别
1. new Message() 直接建立对象,没什么好说的


2.---->[Message]------------------
private static final Object sPoolSync = new Object();//锁对象
private static Message sPool;//消息池的链表首
private static int sPoolSize = 0;//当前消息池的大小
private static final int MAX_POOL_SIZE = 50;//消息池的最大尺寸

---->[Message#obtain]------------------
public static Message obtain() {
    synchronized (sPoolSync) {//同步锁
        if (sPool != null) {//若是消息池不为空
            Message m = sPool;//将sPool对象赋值给m对象
            sPool = m.next;//m的next赋值给sPool对象
            m.next = null;//将m的next置空
            m.flags = 0; // clear in-use flag
            sPoolSize--;//消息池的大小-1
            return m;//将消息返回
        }
    }
    return new Message();//若是消息池为空时,返回新的Message对象
}
|-- 这里很明显使用了单链表,将一个消息从消息池中出列。
|-- 维护消息池的好处不用多说,避免频繁建立和销毁Message,
|-- 好比频繁地发送消息(轮播图),每次切换一下发一个消息,使用消息池维护会更好

3.---->[Handler#obtainMessage]------------------
public final Message obtainMessage(){
    return Message.obtain(this);
}

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

|-- 获取Message后将target设置成当前handler,这一步enqueueMessage中已经有了,因此二者同样
|-- 除此以外Message还有不少重载的 `Message obtain`,都是基于Message.obtain,
|-- 同时再为其设置一些属性,本质上也没有什么太大的区别,本身看一下就好了
复制代码

4.MessageQueue消息队列

Message中并无为消息池中添加消息的方法,那么消息池是怎么实现的?
Handler#enqueueMessage为切入点,看一下这个消息是如何加入消息队列中的

---->[Handler#enqueueMessage]------------------------
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//设置当前消息的target为本Handler
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

---->[MessageQueue#enqueueMessage]------------------------
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {//target为null,即没有对应的Handler,抛异常
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {//消息已经在使用,抛异常
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    synchronized (this) {//this同步锁
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
        msg.markInUse();
        msg.when = when;//设置入队时间
        Message p = mMessages;//将mMessages,即队首赋给p
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {//p为空
            //新建队列头,若是阻塞,唤醒事件队列
            msg.next = p;//当前消息做为队列首
            mMessages = msg;//维护队首
            needWake = mBlocked;
        } else {//表示当前消息队列中有消息了
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;//声明前一个消息
            for (;;) {//至关于while(true)的做用
                prev = p;//将原来的队首元素赋给prev变量
                p = p.next;//将p的下一个消息赋值给p
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; //将当前消息的下一指向到p
            prev.next = msg;//prev指向当前消息
        }
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

>看文字估计挺晕的,以上面三个消息为例,分析一下他们加入的流程
复制代码

第一条消息入队.png

当第二条消息入队时:msg:张风捷特烈
Message p = mMessages  p:玉面奕星龙 不为空,走下面
Message prev;//声明前一个消息
for (;;) {//至关于while(true)的做用
    prev = p;//prev:玉面奕星龙
    p = p.next;//p.next =null,执行后 p=null
    if (p == null || when < p.when) {
        break;
    }
    if (needWake && p.isAsynchronous()) {
        needWake = false;
    }
}
msg.next = p; //张风捷特烈-->null
prev.next = msg;//玉面奕星龙-->张风捷特烈-->null


当第三条消息入队时:msg:百里巫缨
Message p = mMessages  p:玉面奕星龙 不为空,走下面
Message prev;//声明前一个消息
for (;;) {//至关于while(true)的做用
    //第一次循环--prev:玉面奕星龙
    //第二次循环--prev:张风捷特烈
    prev = p;
    //第一次循环--p.next = 张风捷特烈,执行后 p=张风捷特烈
    //第二次循环--p.next = null,执行后 p=null
    p = p.next;
    if (p == null || when < p.when) {
        break;
    }
    if (needWake && p.isAsynchronous()) {
        needWake = false;
    }
}
msg.next = p; //百里巫缨-->null,此时prev:张风捷特烈
prev.next = msg;//玉面奕星龙-->张风捷特烈-->百里巫缨-->null

|-- 因而可知,每添加一条消息都是添加到队尾
复制代码

5.Looper的loop方法

将消息加入队列以后是如何取出的?又如何触发Handler的dispatchMessage回调方法?
这里略去了打日志的一些语句,可见loop方法一直将调用queue.next()直到msg == null
在拿到消息后出发msg.target.dispatchMessage(msg);而后就豁然开朗了
但当没有消息时MessageQueue#next()会被阻塞,而致使loop阻塞。因此next没法让轮循中止
要关闭循环使用MessageQueue#quit。

---->[Looper#loop]---------
public static void loop() {
    //获取当前线程的Looper对象
    final Looper me = myLooper();
    if (me == null) {//若是为空,报异常。说明当前线程没有Looper对象
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.")
    }
    //queue使用的是Looper中的mQueue(在构造函数中被初始化)
    final MessageQueue queue = me.mQueue;
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    for (;;) {//至关于while(true)的做用
        Message msg = queue.next(); // 消息
        if (msg == null) {
            return;
        }
        //略...
        final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        //略...
        final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        final long end;
        try {
            //在这里调用了msg.target即该handler的dispatchMessage方法
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
         //略...
        msg.recycleUnchecked();
    }
}

---->[MessageQueue#next]---------------
Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
    int pendingIdleHandlerCount = -1; 
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        nativePollOnce(ptr, nextPollTimeoutMillis);//这里用来一个native方法
        synchronized (this) {
            //尝试检索下一条消息。若是发现返回。
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;//前一个msg
            Message msg = mMessages;//当前msg为队首
            if (msg != null && msg.target == null) {//通常都有target
                // 被障碍物挡住了。在队列中查找下一个异步消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 下一条消息没有准备好。设置超时以在什么时候唤醒
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integ
                } else {
                    //获取一个msg-------
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 没有消息了
                nextPollTimeoutMillis = -1;
            }
            // 如今全部挂起的消息都已完成,请处理退出消息
            if (mQuitting) {
                dispose();
                return null;
            }
   
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandl
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the hand
            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;
        // While calling an idle handler, a new message could have been delivere
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

---->[Handler#dispatchMessage]---------------
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {//若是msg有回调
        handleCallback(msg);//处理msg的callback 
    } else {
        if (mCallback != null) {//这个上面举例说明过,不说了
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);//回调覆写的handleMessage方法
    }
}

---->[Handler#handleCallback]---------------
private static void handleCallback(Message message) {
    message.callback.run();
}
复制代码

关于MessageQueue#next方法,无非就是让消息出队,没有消息时next会一直阻塞
这里涉及了native的方法,以及控制next的阻塞来完成延迟触发,这里native不展开,
想深刻的,这里推荐一篇文章Android MessageQueue消息循环处理机制


5、Handler#postXXX与Message的callback

1.dispatchMessage方法分析

不知道你有没有注意到,msg里有的callback,为了强调dispatchMessage,这里再看一次

dispatchMessage的流程.png

---->[Handler#dispatchMessage]---------------
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {//若是msg有回调
        handleCallback(msg);//处理msg的callback 
    } else {
        if (mCallback != null) {//这个上面举例说明过,不说了
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);//回调覆写的handleMessage方法
    }
}

---->[Handler#handleCallback]---------------
private static void handleCallback(Message message) {
    message.callback.run();
}
复制代码

2.既然msg能够添加一个Runnable的callback那试一下呗

不幸的事callback是包访问级别的,没有提供set方法,因此用不了
可是提供了一个obtain的重载,能够放置callback

---->[Message#obtain(Handler, Runnable)]
public static Message obtain(Handler h, Runnable callback) {
    Message m = obtain();
    m.target = h;
    m.callback = callback;
    return m;
}
------------------------------------------------------
/**
 * 做者:张风捷特烈<br/>
 * 时间:2019/1/25/025:14:24<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:当msg自身有Runnable回调时
 */
public class HandlerMsgWithCbkActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Handler.Callback callback = msg -> {
            msgTv.setText("回调的handleMessage");
            return true;
        };

        mHandler = new Handler(callback){
            @Override
            public void handleMessage(Message msg) {
                msgTv.setText("覆写的handleMessage");

            }
        };

        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);

        msgTv.setOnClickListener(v -> {
            Thread thread = new Thread(() -> {

                Message msgObtain = Message.obtain(mHandler, new Runnable() {
                    @Override
                    public void run() {
                        msgTv.setText("Message + Runnable");
                    }
                });
                msgObtain.what = 0x02;
                msgObtain.obj = "张风捷特烈";
                mHandler.sendMessageDelayed(msgObtain, 3000);
            });
            thread.start();
        });
    }
}

|--运行结果以下,结合dispatchMessage方法分析图,应该足以说明
复制代码

jieguo.png


3.Handler的几个postXXX方法

post(Runnable r).png

boolean post(Runnable r) post一个Runnable
boolean postAtTime(Runnable r, long uptimeMillis) 定时
boolean postAtTime(Runnable r, Object token, long uptimeMillis) 加token
boolean postDelayed(Runnable r, long delayMillis) 演示
boolean postAtFrontOfQueue(Runnable r) post到队首

---->[Handler#post]-----------------
public final boolean post(Runnable r){
   return  sendMessageDelayed(getPostMessage(r), 0);
}

---->[Handler#getPostMessage]-----------------
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

|-- 可见post也没有多么高大上,只是调用了sendMessageDelayed而已
|-- 其中的Message经过getPostMessage获取,在getPostMessage中
|-- 经过Message.obtain()从消息池中取出一个消息,并添加callback而已
|-- 后面几个方法差很少,只是给Message多添一点信息而已,Message理解了,就不成问题
|-- 这几个方法至关于Handler给咱们封装了一下,要完成上面的测试,能够:

---->[HandlerMsgWithCbkActivity]-----------------
msgTv.setOnClickListener(v -> {
    Thread thread = new Thread(() -> {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                msgTv.setText("Message + Runnable");
            }
        }, 3000);
    });
    thread.start();
});

|-- 注意,使用postXXX,会让Handler.callback和覆写的handleMessage失效  
|-- 由于其本质上是经过Message的callback,前面已经讲了Message.callback一旦存在  
|-- 是不会再走上二者的。
复制代码

终曲、回看Handler:

这时候回头看一下Handler背后的消息机制:

消息承载单体:Message  
消息管理器:MessageQueue
消息机制驱动力:Looper  
消息处理器:Handler

---->[为告终尾点题,编个故事吧]---注:本故事纯属虚构-------------
传说在100亿年前,宇宙不止一个,人们生活的宇宙被称为main宇宙
除了main宇宙以外,称为子宇宙,因为宇宙众多,被人们称为三千宇宙
有些人试图在子宇宙改变本身的样子(包括服饰),开始新的生活,
但无一例外,所有灰飞烟灭,非main宇宙没法改变容饰成了平行宇宙法则
但main宇宙中人员众多,资源相对匮乏,不少人只能去子宇宙去获取资源

一个叫TextView的女生想要一件漂亮的衣服,做为男朋友的Handler义无反顾独闯子宇宙,
他爆出了3件很是漂亮的衣服,知道让TextView直接来到子宇宙穿上的话,她便会马上灰飞烟灭  
因而他用3个空间立方(Message)将3件衣服分别装入其中,并标识message的target是本身  
而后3个空间立方被依次放入了[平行宇宙传送台(MessageQueue)],
main宇宙中的强大Looper能源驱动着[平行宇宙传送台],自从三千宇宙诞生的那刻就开启了(Looper.loop)  
当空间立方传递到主宇宙时,空间立方传根据target找到本身的主人曾经的嘱托(handleMessage) 
而后将三件美丽的服饰依次给TextView穿上,这样就实现了子宇宙资源对宇宙的传送  

有些常年在子宇宙工做的人,也常用这种机制,寄一封回家,传达思念与祝福
而这些,就是当时他们的平常生活...
复制代码
最后一个问题:Handler只是能在主宇宙和子宇宙间传递资源吗?

每一个子宇宙均可以拥有仅属于本身的一个Looper,子宇宙间也能够经过Handler进行通讯

/**
 * 做者:张风捷特烈<br/>
 * 时间:2019/1/25/025:14:24<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:子线程间通讯
 */
public class HandlerOtherActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);
        msgTv.setOnClickListener(v -> {
            new Thread("第一子宇宙") {//第一子宇宙
                @Override
                public void run() {
                    Message newMsg = new Message();
                    newMsg.what = 0x01;
                    newMsg.obj = "玉面奕星龙";
                    mHandler.sendMessage(newMsg);
                    Log.e("HandlerOtherActivity", "当前线程名称: " + Thread.currentThread().getName() + " 发送:" + ne
                }
            }.start();
        });
        new Thread("第二子宇宙") {//第二子宇宙
            @Override
            public void run() {
                Looper.prepare();//让当前子宇宙生成--looper能源
                //Handler经过第二子宇宙的looper能源能源构造
                mHandler = new Handler(msg -> {
                    Log.e("HandlerOtherActivity", "当前线程名称: " + Thread.currentThread().getName() + " 接收:" + ms
                    return false;
                });
                Log.e("HandlerOtherActivity", "run: ");
                Looper.loop();//looper能源启动--此时该线程会阻塞------下面的方法没法执行
                Log.e("HandlerOtherActivity", "run:-------- ");
            }
        }.start();
    }
}

|-- 注意点:当第一线程要向第二线程传递数据,mHandler要拥有第二线程的looper
|-- 也就是让Handler在第二线程中建立,下图已经很明确让的表达出:
|-- 第一线程向第二线程传递了一条信息,并且第二线程会阻塞在Looper.loop()是,下一句没法打印
复制代码

子线程经过handler通讯.png


为了让你对Looper有更深的认识,换一种写法

下面的写法若是你看懂了,handler机制就不在话下了
一句话:在main线程中使用线程2的looper建立Handler,在线程1中经过Handler发送消息
结果消息还是在线程2中执行的,看日志并未改变:(只有looper在哪一个线程,消息就会发到哪一个线程)

子线程经过handler通讯.png

/**
 * 做者:张风捷特烈<br/>
 * 时间:2019/1/25/025:14:24<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:子线程间通讯
 */
public class HandlerOtherActivity extends AppCompatActivity {
    private TextView msgTv;
    private Handler mHandler;

    private Looper mOtherLooper;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.ac_handler);
        msgTv = findViewById(R.id.id_tv_handler);

        msgTv.setOnClickListener(v -> {

            new Thread("第一子宇宙") {//第一子宇宙
                @Override
                public void run() {
                    Message newMsg = new Message();
                    newMsg.what = 0x01;
                    newMsg.obj = "玉面奕星龙";
                    mHandler.sendMessage(newMsg);
                    Log.e("HandlerOtherActivity", "当前线程名称: " + Thread.currentThread().getName() + " 发送:" + newMsg.obj);
                }
            }.start();
        });

        new Thread("第二子宇宙") {//第二子宇宙
            @Override
            public void run() {
                Looper.prepare();//让当前子宇宙生成--looper能源
                mOtherLooper = Looper.myLooper();

                Log.e("HandlerOtherActivity", "run: ");
                Looper.loop();//looper能源启动--此时该线程会阻塞------下面的方法没法执行
                Log.e("HandlerOtherActivity", "run:-------- ");
            }
        }.start();

        try {
            Thread.sleep(10);//睡10ms让mOtherLooper能够初始化
//            Handler经过第二子宇宙的looper能源能源构造
            mHandler = new Handler(mOtherLooper, msg -> {
                Log.e("HandlerOtherActivity", "当前线程名称: " + Thread.currentThread().getName() + " 接收:" + msg.obj);
                return false;
            });

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
复制代码