设为首页 加入收藏

TOP

详解 Handler 消息处理机制(附自整理超全 Q&A)(一)
2019-08-26 06:25:08 】 浏览:85
Tags:详解 Handler 消息 处理 机制 整理 Q&A

Android 为什么要用消息处理机制

如果有多个线程更新 UI,并且没有加锁处理,会导致界面更新的错乱,而如果每个更新操作都进行加锁处理,那么必然会造成性能的下降。所以在 Android 开发中,为了使 UI 操作是线程安全的,规定只许主线程即 UI 线程可以更新 UI 组件。但实际开发中,常常会遇到多个线程并发操作 UI 组件的需求,于是 Android 提供了一套消息传递与处理机制来解决这个问题。也就是在非主线程需要更新 UI 时,通过向主线程发送消息通知,让主线程更新 UI。

当然消息处理机制不仅仅可以用来解决 UI 线程安全问题,它同时也是一种线程之间沟通的方式。

Looper

Looper 即消息循环器,是消息处理机制的核心,它可以将一个普通线程转换为一个 Looper 线程。所谓的 Looper 线程就是一个不断循环的线程,线程不断循环的从 MessageQueue 中获取 Message,交给相应的 Handler 处理任务。在 Looper 类的注释介绍中,我们可以得知通过两个静态方法 Looper.prepare()Looper.loop() 就可以将线程升级成 Looper 线程:

class LooperThread extends Thread {
    public Handler mHandler;
    
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();
        
        // 注意:一定要在两个方法之间创建绑定当前Looper的Handler对象,
        // 否则一旦线程开始进入死循环就没法再创建Handler处理Message了
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // 处理收到的消息
                
            }
        };
        
        // 开始循环处理消息队列
        Looper.loop();
    }
}

Looper.prepare()

该方法在线程中将 Looper 对象定义为 ThreadLocal 对象,使得 Looper 对象成为该线程的私有对象,一个线程最多仅有一个 Looper。并在这个 Looper 对象中维护一个消息队列 MessageQueue 和持有当前线程的引用,因此 MessageQueue 也是线程私有。

public final class Looper {

    // 每个线程仅包含一个的Looper对象,定义为一个线程本地存储(TLS)对象
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
    // 每个Looper维护一个唯一的消息队列
    final MessageQueue mQueue;
    
    // 持有当前线程引用
    final Thread mThread;
    
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    
    public static void prepare() {
        prepare(true);
    }

    // 该方法会在调用线程的TLS中创建Looper对象,为线程私有
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            // 试图在有Looper的线程中再次创建Looper对象将抛出异常
            throw new RuntimeException(
                "Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
}

Looper.loop()

该方法启动线程的循环模式,从 Looper 的 MessageQueue 中不断的提取 Message,再交由 Handler 处理任务,最后回收 Message 供以后复用。

public static void loop() {
    // 得到当前线程的Looper对象
    final Looper me = myLooper();
    if (me == null) {
        // 线程没有调用Looper.prepare(),所以没有Looper对象
        throw new RuntimeException(
            "No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 得到当前消息队列
    final MessageQueue queue = me.mQueue;

    ...

    // 开始循环
    for (;;) {
        // 从消息队列中获取下一个Message,该方法可以被阻塞
        Message msg = queue.next();
        
        ...
        
        // 将Message推送到Message中的target处理
        // 此处的target就是发送该Message的Handler对象
        msg.target.dispatchMessage(msg);
        
        ...
        
        // 回收Message,这样就可以通过Message.obtain()复用
        msg.recycleUnchecked();
    }
}

Handler

Handler 可以称之为消息处理者。Looper 线程不断的从消息队列中获取消息,而向消息队列中推送消息的正是 Handler 这个类。

Handler 在工作线程通过 sendMessage() 向 MessageQueue 中推送 Message,而主线程 Looper 循环得到 Message 后,即可得到发出该 Message 的 Handler 对象(Handler 发送消息时将自身引用赋值给 message.target),再通过 Handler 对象的 dispatchMessage()handleMessage() 方法处理相应的任务。这样我们就可以通过 Handler 同时完成了异步线程的消息发送与消息处理两个功能。

Handler 默认构造方法会关联当前线程的 Looper 对象,一个线程只能有一个 Looper 对象,但可以有多个 Handler 关联这个 Looper 对象。Handler 也提供一些构造方法关联自定义的 Looper 对象。

public class Handler {
    
    final Looper mLooper;
    final MessageQueue mQueue;
    final Callback mCallback;
    
    public Handler() {
        this(null, false);
    }
    
    public Handler(boolean async) {
        this(null, async);
    }
    
    public Handler(Callback callback) {
        this(callback, false);
    }
    
    public Handler(Looper looper) {
        this(looper, null, false);
    }
    
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    
    /**
     * @hide
     */
    public Handler(Callback
首页 上一页 1 2 3 4 5 6 下一页 尾页 1/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇解决Android Studio安装过程中“S.. 下一篇一起学Android之Fragment

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目