前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )

【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )

作者头像
韩曙亮
发布2023-03-27 20:42:42
1.3K0
发布2023-03-27 20:42:42
举报

文章目录

I . Handler 机制简介


Handler 机制是 Android 中最重要的 异步通信 机制 ;

1 . Handler 机制作用 : 将需要执行的任务分配给其它线程 ;

① 子线程更新 UI : 在子线程中更新 UI , 就是在子线程中将刷新 UI 的任务分配给了主线程 ; ( 子线程刷新 UI 会崩溃 )

② 主线程网络操作 : 在主线程中 , 将网络通信等耗时的操作分配给子线程 ( 该子线程需要转成 Looper 线程 ) , 避免 UI 卡顿 ; ( 主线程访问网络会崩溃 )

2 . Handler 机制中涉及到的组件 :

① Handler ( 消息处理者 ) : 定义具体的代码操作逻辑 , 处理收到消息 ( Message ) 后的具体操作 ;

② Message ( 消息 ) : 定义具体消息 , 其中可以封装不同的变量 , 为 Handler 指定操作的类型 , 或执行操作所需的数据 ;

③ Looper ( 消息遍历者 ) : 消息的遍历者 , 遍历 MessageQueue 中的消息 , 分发给 Handler 处理 ;

④ MessageQueue ( 消息队列 ) : 封装在 Looper 中 , 每个 Looper 中封装了一个 MessageQueue , 是 Looper 消息遍历的重要组件 , 用户不直接调用该组件 ;

3 . Handler 机制中的 封闭性 与 线程交互 :

① 线程内部相对封闭的运行系统 : 整个 Looper 线程内部是一个封闭运行的系统 , Looper 一直不停的再遍历 MessageQueue , 将 消息 或 操作 取出 , 交给 Handler 执行 ;

② 线程交互 : Handler 还有另外一个职责就是负责与外部线程的交互 , 在外部线程中调用 Handler 将消息回传给本 Looper 线程 , 放入 MessageQueue 队列中 ;

4 . Message ( 消息 ) 的运行路径 ( 重点 ) : 在外部线程中 , 调用 Looper 线程的 Handler 成员 , 将 Message ( 消息 ) 发送给 Looper 线程中的 MessageQueue ( 消息队列 ) , 然后 Looper 轮询该 消息队列时 , 又将该消息交给 Handler 进行处理 ;

Message -> Handler ( 发送 ) -> MessageQueue ( 存储 ) -> Looper ( 轮询 ) -> Handler ( 执行 )

II . Handler 机制 Handler Message Looper MessageQueue 四组件对应关系


Handler , Message , Looper , MessageQueue 四组件对应关系 :

Handler 机制中的上述四者的对应关系 : 一个线程中只能有一个 Looper 及 Looper 中封装的 MessageQueue , 每个 Looper 可以为多个 Handler 调度消息 , Message 消息可以有无数个 ;

Looper 是 线程本地存储的对象 ( ThreadLocal ) , 一个线程只能存在一个 , MessageQueue ( 消息队列 ) 定义在 Looper 内部 , 每个 Looper 中只定义了一个 MessageQueue ( 消息队列 ) , 因此每个线程也只能有一个 MessageQueue ;

线程 与 Looper ( 消息遍历者 ) 是一对一关系 , Looper ( 消息遍历者 ) 与 MessageQueue ( 消息队列 ) 是一对一的关系 , Looper ( 消息遍历者 ) 与 Handler ( 消息处理者 ) 是一对多的关系 , Message ( 消息 ) 可以有很多 ;

III . Handler ( 消息处理者 )


1 . Handler 创建 : 这里注意 只能在 Looper 线程中创建 Handler , 普通线程不能创建 Handler ;

① 主线程 : 主线程中可以直接创建 Handler , 因为在点击应用图标后就会 启动主线程 ActivityThread , 此时就已经将 Looper 实例化好了 , 因此我们在 Activity 中 , 可以任意创建多个 Handler , 并直接使用 ;

public final class ActivityThread {
	...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
		//创建 ActivityThread 线程, 并运行
        ActivityThread thread = new ActivityThread();
        //attach 方法 进行 thread 的最初初始化操作 
        thread.attach(false);
        ...
        Looper.loop();
        ...
    }//main
    ...
}//ActivityThread

② 子线程 : 子线程如果要创建 Handler , 需要先 调用 Looper.prepare() 方法 , 将线程转为 Looper 线程 , 因为 创建 Handler 时 , 会关联线程的 Looper 对象 , 普通的子线程是没有 Looper 对象的 , 调用 Looper.prepare() 方法即可为该线程创建 Looper 对象 , 该线程也就转为了 Looper 线程 ;

public class handler {
	...
	//获取 Looper 对象后 , 可以从 Looper 对象中获取 MessageQueue
	//关联后 , Handler 发送消息时 , 才能将消息精准的发送给
	final MessageQueue mQueue;
	//Handler 需要与线程的唯一 Looper 对象关联
    final Looper mLooper;  
    ...
    public Handler() {
    	...
		mLooper = Looper.myLooper()
		if (mLooper == null) {
			throw new RuntimeException(
				"Can't create handler inside thread that has not called Looper.prepare()");
		}
		...
		mQueue = mLooper.mQueue;
		...
	}
	...
}

2 . Handler 对象个数 : 每个 Looper 线程可以创建多个 Handler , 只要该 Handler 与 Looper 和 MessageQueue 关联 , 就可以将 消息 ( Message ) 发送给 Looper 线程中的 MessageQueue 中 ; Looper 轮询该 消息队列 ( MessageQueue ) , 将消息再次分发给对应的 Handler 进行处理 ;

IV . Looper ( 消息遍历者 )


1 . Looper 线程 : 如果要将 Handler , Looper 机制引入到线程中 , 使某线程具有接收 Message ( 消息 ) , 执行某项操作的功能 , 需要将该线程转为 Looper 线程 ;

2 . Looper 线程可执行的操作 : 一个线程如果被转为 Looper 线程 , 那这个线程运行后只能接收 Message 消息 , 执行对应的操作 , 运行后永远卡在 loop 循环遍历的 while (true) 循环中 , 使用 quit() 方法才能退出 ;

3 . Loop.prepare() 方法 : 该方法是将 普通子线程 转为 Looper 线程最终要的方法 , 该方法的主要作用是 创建 Looper , 然后将 Looper 对象放入 ThreadLocal 对象中存储 ; 线程只有创建了 Looper 对象才能创建 Handler , 将该 Looper 对象及其中封装的 MessageQueue 与 Handler 进行关联 , Handler 才可以进行消息的调度 ; 如果线程中没有 Looper 对象 , 创建 Handler 会报运行时异常 ;

public final class Looper {
	...
	// sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
	...
	private static void prepare(boolean quitAllowed) {
    	if (sThreadLocal.get() != null) {
        	throw new RuntimeException("Only one Looper may be created per thread");
    	}
    	sThreadLocal.set(new Looper(quitAllowed));
	}
	...
}

4 . Loop.loop() 方法 : 一旦调用了该方法 , 就意味着该 Looper 线程进入到了轮询 MessageQueue 的阶段 , 这是一个无限死循环 , 调用了该方法后 , Handler 发送消息 , 线程才能处理对应的业务逻辑 ;

调用 quit() 方法 , 可以终止该遍历 MessageQueue 操作 ;

下面代码删除了大部分代码 , 只留下 循环遍历 和 调度 Message 信息给 Handler 进行处理 ;

public static void loop() {
    final Looper me = myLooper();
    ...
    final MessageQueue queue = me.mQueue;
    ...
    for (;;) {
        Message msg = queue.next(); // 阻塞
        if (msg == null) {
            // 循环遍历退出
            return;
        }
        ...
        try {
        	//调度 Message 信息给 Handler 进行处理 
            msg.target.dispatchMessage(msg);
            ...
        } 
        ...
    }
}

V . Looper 子线程


1 . Looper 线程就是在普通线程的基础是哪个 , 加入了 Looper 用于消息调度 , 然后将消息转发给 Handler 进行处理 , 这样就实现了 在其它线程中 , 将任务异步分配给该 Looper 线程 ;

2 . Android 中的主线程本身就是 Looper 线程 , 整个 Looper 循环遍历消息的过程由系统完成 , 用户只需要自定义一个 Handler 成员 , 即可在子线程中调用该 Handler 将消息发送到主线程 , 在主线程执行相关操作 , 实现了将异步任务分配给主线程 , 这是子线程刷新 UI 的重要途径 ;

3 . 普通子线程 转为 Looper 子线程 流程 :

① 定义 Handler 成员变量 : 在线程 Thread 派生类中 , 定义 Handler 类型的成员变量 ;

② Looper 初始化 : 调用 Looper.prepare() 静态方法 , 该方法的作用是创建 Looper 变量 , 存储在了 ThreadLocal 中 , 将当前普通线程转为 Looper 线程 ;

③ 实例化 Handler 成员 : 一定要在 Looper.prepare() 之后实例化成员 , 因为如果在之前实例化 , Handler 与 Looper 无法产生关联 ;

④ 轮询消息队列 : 调用 Looper.loop() 方法 , 轮询消息队列 ( MessageQueue ) ;

4 . 实例化 Handler 成员时机 :

① 实例化时机 : 必须要在调用 Looper.prepare() 之后实例化才可以 , 因为实例化 Handler 对象时 , 会获取当前线程的 Looper , 如果为空 , 直接抛异常 ;

② Looper 对象创建 : Looper.prepare() 的作用就是创建 Looper 对象 , 将其放入 ThreadLocal 对象中存储 , 保证线程有且只有一个 Looper 对象 ;

public class handler {
	...
	//获取 Looper 对象后 , 可以从 Looper 对象中获取 MessageQueue
	//关联后 , Handler 发送消息时 , 才能将消息精准的发送给
	final MessageQueue mQueue;
	//Handler 需要与线程的唯一 Looper 对象关联
    final Looper mLooper;  
    ...
    public Handler() {
    	...
		mLooper = Looper.myLooper()
		if (mLooper == null) {
			throw new RuntimeException(
				"Can't create handler inside thread that has not called Looper.prepare()");
		}
		...
		mQueue = mLooper.mQueue;
		...
	}
	...
}

5 . 普通子线程 转为 Looper 子线程 代码示例 :

package kim.hsl.handler;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import androidx.annotation.NonNull;

/**
 * 将普通线程转为 Looper 线程
 *
 * 1. 定义 Handler 成员 ( 可以定义若干个 )
 * 2. Looper.prepare()
 * 3. 实例化 Handler 成员
 * 4. Looper.loop()
 *
 * @author hsl
 */
public class LooperThread extends Thread {
    /**
     * 1. 定义时不要实例化
     * Handler 实例化需要关联 Looper 对象
     * Looper 对象在 Looper
     */
    private Handler handler;

    @Override
    public void run() {
        super.run();
        
        //2. 将线程转为 Looper 线程
        //主要是创建 Looper 放入 ThreadLocal 对象中
        Looper.prepare();

        //3. 创建 Handler 必须在 Looper.prepare() 之后, 否则会崩溃
        handler = new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                //TODO 处理 Handler 相关业务逻辑
            }
        };

        //4. Looper 开始轮询 MessageQueue, 将消息调度给 Handler 处理
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }
}

VI . Handler 发送 消息 种类


Handler 既可以发送静态的 消息 ( Message ) , 又可以发送动态的 操作 ( Runnable ) ;

当 Handler 所在的 Looper 线程接收到 消息 ( Message ) 时 , Looper 轮询到该 消息 ( Message ) 后 , 执行该消息对应的业务逻辑 , 这些逻辑一般都是在 Handler 中提前定义好的 ;

当 Handler 所在的 Looper 线程接收到 操作 ( Runnable ) 时 , Looper 轮询到该 操作 ( Runnable ) 后 , 直接运行该 Runnable 中的 run() 方法 ;

VII . Handler 机制总结


1 . Handler 机制运行流程 : Message 通过 Handler 发送给 Looper 线程的 MessageQueue , Looper 轮询 MessageQueue 将 Message 交给 Handler 执行 ;

2 . 线程异步调用 ( 作用 ) : 子线程刷新主线程 UI ( 子线程调用主线程 ) , 主线程调用子线程异步网络操作 ( 主线程调用子线程 ) ;

3 . 子线程转 Looper 线程 : 定义Handler 成员 ( 可以多个 ) , Loop.prepare() , Handler 初始化 ( 必须在 prepare 之后 ) , Looper.loop() ;

4 . 四组件关系 :

1

线程

\Leftrightarrow
1

Looper

\Leftrightarrow
1

MessageQueue

\Leftrightarrow
n

Handler

\Leftrightarrow
m

Message ;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • I . Handler 机制简介
  • II . Handler 机制 Handler Message Looper MessageQueue 四组件对应关系
  • III . Handler ( 消息处理者 )
  • IV . Looper ( 消息遍历者 )
  • V . Looper 子线程
  • VI . Handler 发送 消息 种类
  • VII . Handler 机制总结
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档