Android中Handler、Looper、MessageQueue的工作原理

简介:

为了更好的理解Handler的工作原理,先介绍一下与Handler一起工作的几个组件。

  • Message: Handler接收和处理的消息对象

  • Looper:每个线程只能拥有一个Looper。它的loop方法负责读取MessageQueue中的消息,之后把消息交给发送该消息的Handler处理

  • MessageQueue:消息队列,使用先进先出的方式来管理Message。程序创建Looper对象时会在它的构造器中创建MessageQueue对象。下面是Looper的构造函数:

?
1
2
3
4
5
private  Looper() {
     mQueue =  new  MessageQueue(); //这里创建MessageQueue,这个Queue就负责管理消息
     mRun =  true ;
     mThread = Thread.currentThread();
}

  • Handler,它的作用有两个——发送消息和处理消息。程序使用Handler发送消息,被Handler发送的消息必须被送到指定的MessageQueue。也就是说,如果希望Handler正常工作,必须在当前线程中有一个MessageQueue,否则消息就没地方保存了。而MessageQueue是由Looper管理的,因此必须在当前线程中有一个Looper对象,可以分如下两种情况处理:

  1. 主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可以通过Handler来发送消息和处理消息了。

  2. 程序员自己启动的子线程中,必须自己创建一个Looper对象,并启动它。调用它的prepare()方法即可创建Looper对象。

prepare()方法保证每个线程最多只有一个Looper对象:

?
1
2
3
4
5
6
public  static  final  void  prepare() {
     if  (sThreadLocal.get() !=  null ) {
         throw  new  RuntimeException( "Only one Looper may be created per thread" );
     }
     sThreadLocal.set( new  Looper()); //这里创建Looper对象并放到ThreadLocal中
}

然后调用Looper的静态loop()方法来启动它。loop()方法使用一个死循环不断取出MessageQueue中的消息,并将其分发给对应的Handler进行处理:

?
1
2
3
4
5
6
7
8
9
10
for (;;) {
     Message msg = queue.next(); //获取Queue中的下一个消息,如果没有,将会阻塞
     if  (msg ==  null ) {
         //如果消息为null,表明MessageQueue正在退出
         return ;
     }
     ...
     msg.target.dispatchMessage(msg);
     ...
}


在线程中使用Handler的步骤如下:

  1. 调用Looper.prepare()为当前线程创建Looper对象,这将自动创建与之配套的MessageQueue

  2. 创建Handler子类的实例,重写handleMessage(Message msg)分发,该方法负责处理来自其他线程的消息

  3. 调用Looper.loop()启动Looper

例:输入一个整数,单击“计算”按钮,计算小于这个整数的所有质数。Activity的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public  class  CalPrime  extends  Activity {
     static  final  String UPPER_NUM =  "upper" ;
     EditText etNum;
     CalThread calThread;
     //定义一个线程类
     class  CalThread  extends  Thread {
         public  Handler mHandler;
         public  void  run() {
             Looper.prepare();  //Step1.创建Looper对象
             mHandler =  new  Handler() {  //Step2.创建Handler对象
                 //重写处理Message的方法
                 @Override
                 public  void  handleMessage(Message msg) {
                     if  (msg.what ==  123 ) {
                         int  upper = msg.getData().getInt(UPPER_NUM);
                         List<Integer> nums =  new  ArrayList<Integer>();
                         outer:
                         for  ( int  i =  2 ; i <= upper; i++) {
                             //用i % (从2开始到i的平方根的所有整数)
                             for  ( int  j =  2 ; j <= Math.sqrt(i); j++) {
                                 // 如果可以整除,则不是质数
                                 if  (i !=  2  && i % j ==  0 ) {
                                     continue  outer;
                                 }
                             }
                             nums.add(i);
                         }
                         Toast.makeText(CalPrime. this , nums.toString(), Toast.LENGTH_LONG).show();
                     }
                 }
             };
             Looper.loop();  //Step3.启动Looper
         }
     }
     
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         etNum = (EditText)findViewById(R.id.etNum);
         calThread =  new  CalThread();
         calThread.start();
     }
     
     //为按钮提供处理函数
     public  void  cal(View source) {
         Message msg =  new  Message();
         msg.what =  0x123 ;
         Bundle bundle =  new  Bundle();
         bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));
         msg.setData(bundle);
         //向新线程中的Handler发送消息
         calThread.mHandler.sendMessage(msg);
     }
}
目录
相关文章
|
19天前
|
安全 Shell Android开发
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
30 0
|
19天前
|
安全 Android开发
Android13 Root实现和原理分析
Android13 Root实现和原理分析
48 0
|
19天前
|
Java Android开发
Android系统 获取用户最后操作时间回调实现和原理分析
Android系统 获取用户最后操作时间回调实现和原理分析
21 0
|
19天前
|
消息中间件 网络协议 Java
Android 开发中实现数据传递:广播和Handler
Android 开发中实现数据传递:广播和Handler
16 1
|
19天前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
40 0
|
5天前
|
前端开发 Java Android开发
Android UI底层绘制原理
Android UI底层绘制原理
11 0
|
19天前
|
存储 Java Shell
Android系统 实现低内存白名单防LMK原理分析
Android系统 实现低内存白名单防LMK原理分析
32 0
|
19天前
|
网络协议 Shell Android开发
Android 深入学习ADB调试原理(1)
Android 深入学习ADB调试原理(1)
26 1
|
19天前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
31 0
|
9天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。