彻底掌握Handler,含源码分析

定义

Android 的一种消息传递机制,用于异步处理

背景

为了保证线程安全,Android 只允许主线程更新UI,如果工作线程想要更新UI必须让主线程执行,Handler的出现就是用于工作线程与主线程间的通信

概念

主线程(UI线程):ActivityThread,APP启动时会自动启动一条主线程用于执行UI更新操作

工作线程:用于执行耗时任务(网络请求、计算),避免出现ANR

消息:Message,线程通信的数据单元

消息队列:MessageQueue,先进先出的数据结构(单链表),用于存放消息

处理器:Handler,一个Handler实例必须与一个Looper对象关联,当你创建一个新的Handler,它会和一个Looper进行绑定(不一定是当前线程的Looper,其他线程创建好的Looper也可以),它将向Looper关联的的消息队列发送消息,并在Looper的线程上执行它们

循环器:Looper,一个线程持有一个Looper,一个Looper持有一个MessageQueue,但是一个Looper可以与多个Handler绑定,这样多个Handler将消息传给同一个Looper的消息队列中,由Looper将消息取出分发给不同的Handler(与它绑定的Handler们),从而实现线程通信

使用方式

定义
class MyHandler extends Handler {//子类
    @override
    public void handleMessage(Message msg) {
        //用于处理接收到的消息
    }
}

private Handler myHandler = new Handler() {//匿名内部类
     @override
    public void handleMessage(Message msg) {
        //用于处理接收到的消息
    }
};

发送
//1.sendMessage() 
private Handler myHandler = new MyHandler();
Message msg = Message.botain();
msg.what= 0x22;
msg.msg = 1;
myHandler.sendMessage(msg);

//2.post() 
//在主线程中创建Handler对象myHandler,在工作线程中使用该对象执行post()方法
myHandler.post(new Runnable(){
    @override
    public void run() {
        //直接写你要干什么
    }
})

这两种使用方式底层都是调用了同一个方法sendMessageDelayed,最终通过MQ中的enqueueMessage方法实现消息入队

工作原理

异步通信准备

在线程中创建处理器Handler、循环器Looper及消息队列MessageQueue的对象;主线程创建时自动创建Looper和MessageQueue,工作线程需要手动创建。

  • Handler如果不指定Looper则自动绑定同线程的Looper
  • MQ创建完成后,Looper自动进入消息循环

消息入队

Handler将Message发送到与自己绑定的Looper的MessageQueue

消息循环

  • 消息出队:Looper循环取出MQ中的Message
  • 消息分发:Looper将取出的Message发送给与自己绑定的Handler们

在消息循环的过程中,如果MQ为空了,线程会阻塞

消息处理 

Handler拿到Looper发来的Message后执行操作

下面是Handler实现简单线程通信的示意图:

源码分析

Handler

创建Handler
//经常使用的构造器
public Handler() { 
    this(null, false);
}

//指定Looper的构造器
public Handler(Looper looper) { 
    this(looper, nuul, false); 
}

public Handler(Callback callback, boolean async) {
    ...
    1.指定Looper对象,因为没有指定Looper,所以绑定当前线程的Looper    
    mLooper = Looper.myLooper();

    Handler必须绑定一个Looper对象否则抛异常;所以工作线程中创建Handler之前必须先创建Looper对象
    if (mLooper == null) { throw new RuntimeException(); }

    2.绑定消息队列对象
    mQueue = mLooper.mQueue;
}

public Handler(Looper looper, Callback callback, boolean async) {
    ...
    1.指定Looper对象,因为指定了Looper对象,所以可以直接绑定
    mLooper = looper; 
    2.绑定消息队列对象
    mQueue = looper.mQueue;
}

发送消息
//sendMessage
public final boolean sendMessage(Message msg) { 
    return sendMessageDelayed(msg, 0); 
}
//post
public final boolean post(Runnable r) { 
    return sendMessageDelayed(getPostMessage(r), 0); 
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) { delayMillis = 0; }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    发送消息前先获取到与Handler绑定的Looper对象持有的MQ
    MessageQueue queue = mQueue;
    
    MQ对象必须有,否则无法发送消息
    if (queue == null) { return false; }
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    Handler把消息发送到MQ
    return queue.enqueueMessage(msg, uptimeMillis);
}

分发、处理消息
public void dispatchMessage(Message msg) {
    1.处理post方法发出的消息
    if (msg.callback != null) {
        handleCallback(msg);//也就是回调Runnable中的run方法
    } else {
        ...
        2.处理sendMessage方法发出的消息
        handleMessage(msg);
    }
}

Looper

创建Looper对象
public static void prepare() {
    prepare(true);
}

public static void prepareMainLooper() {
    1.在android系统启动时,会默认创建一个主线程也叫UI线程ActivityThread,会自动调用它的main方法
    prepare(false);
    ...
    sMainLooper = myLooper();
}

private static void prepare(boolean quitAllowed) {
    1.先判断当前线程中有没有Looper对象,因为一个线程只能有一个Looper对象,所以该方法只能调用一次
    if (sThreadLocal.get() != null) {
        throw "Only one Looper may be created per thread"
    }
    2.将Looper对象存放到Thread里
    sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
    1.只要创建了Looper就自动创建了MQ对象
    mQueue = new MessageQueue(quitAllowed);
    ...
    mThread = Thread.currentThread();
}

开启消息循环
public static void loop() {
    1.获取当前Looper的消息队列
    final Looper me = myLooper(); 
    final MessageQueue queue = me.mQueue;
    ...

    2.消息循环
    for(;;) {

        2.1 从消息队列中取出消息
        Message msg = queue.next();
        if (msg == null) {//若取出的消息为空,则线程阻塞
            return; 
        } 

        2.2 派发消息到对应的Handler
        msg.target.dispatchMessage(msg);//把消息派发给message的target属性;target属性实际就是一个Handler对象

        3.释放消息占据的资源
        msg.recycleUnchecked();//其实就是将message里面的属性都赋值0或null
    }
}

MessageQueue

Message next() {
    ...
    1.用于标识队中是否还有消息 0:还有 -1:没了
    int nextPollTimeoutMillis = 0;

    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        2.如果nextPollTimeoutMillis等于-1,队列处于等待状态
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            ...
            if (msg != null) {
                ...
                3.消息出队
                return msg;
            } else {
                4.没有消息了
                nextPollTimeoutMillis = -1;
            }
        }
    }
}

boolean enqueueMessage(Message msg, long when) {
    ...
    synchronized(this) {
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        1.判断消息队列里有没有消息
        if (p == null || when = 0 || when < p.when) {
            2.若没有消息,将当前插入消息作为队头;若此消息队列处于阻塞态,则唤醒
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            ...
            for(;;) {
                3.若有消息,根据消息创建时间插入队列
            }
        }
    }
}

Message 


public static Message obtain() {
    1.Message内部维护了一个Message池,用于Message对象的复用,使用obtain方法就是直接从池内获取
    synchronized (sPoolsSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;//Message是链表?
            m.flags = 0;
            sPoolSize--;
            return m;
        }
    }
    2.若池内无消息对象可用,则还是用关键字new创建
    return new Message();
}

Message内部有很多属性,比如target是Handler等等,可以好好看看

ActivityThread

public static void main(String[] args) {
    ...
    
    1.默认为主线程创建一个Looper对象,同时生成一个MQ对象
    Looper.prepareMainLooper(); 
    
    2.创建主线程
    ActivityThread thread = new ActivityThread();

    3.开启消息循环
    Looper.loop();
}

Handler底层执行方法的流程

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有 朝一 日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值