Android Handler 机制简单讲解

2023-07-14 10:58:23 浏览数 (2)

1. 前言

现在很多项目,可能Handler用的少了。但是如果你去面试,总是避免不了被问Handler原理等等。

下面将汇总介绍Handler的机制,从简单到复杂让大家都能一文就了解。下次被问到时可以有的放矢。

最简单的介绍,Handler就是一个用于处理多线程异步消息的机制。主要用于线程间通信。并不能支持进程间通信。

2. 正文

常见场景为:后台数据或IO线程获取信息,需要更新UI线程进行界面刷新。

而这两者之中的消息通讯,就可以通过Handler进行处理。

整个Handler 使用是由多个模块组合而成,分别分为:

  1. Message:代表需要传递的消息,每个消息都有自己的标签。
  2. MessageQueue :消息队列,通过一个单链表的数据结构来维护消息列表。
  3. Handler:消息入口和出口,负责向MessageQueue中发送消息(Handler.sendMessage()),同时也处理相应的消息事件(Handler.handleMessage()).
  4. Looper:消息分发者,负责不断循环执行Looper.loop将MessageQueue中的消息读取出来,分发给接收者进行处理Message。

2.1 Handler 原理

Android 中的Handler 通信是基于Linux系统的管道通信IPC机制来实现的线程通讯。

Looper.loop方法会不断循环处理Message,其中读取最终会通过JNI调用进入Native层,实现管道通讯。

3. 实例

我们在使用Handler中也有很多需要注意的地方。

3.1 Handler 内存泄漏

Handler 允许我们发送延时消息,但是如果在延时期间用户关闭了Activity,那么该Activity就会出现内存泄漏的问题。

主要是因为Message会持有Handler,而在Java中内部类会持有外部类,也就是Activity会被Handler持有。最终导致Activity无法被销毁,造成泄漏。

解决方法:将Handler定义为静态内部类,弱引用Activity。

实例:

代码语言:javascript复制
public class DemoActivity extends AppCompatActivity{	
	private static class MyHandler extends Handler{		
        //弱引用持有HandlerActivity , GC 回收时会被回收掉
        private WeakReference<DemoActivity> weakReference;        public MyHandler(DemoActivity activity) {            this.weakReference = new WeakReference(activity);
        }        @Override
        public void handleMessage(Message msg) {            DemoActivity activity = weakReference.get();            super.handleMessage(msg);            if (null != activity) {                //执行业务逻辑
                Toast.makeText(activity,"handleMessage",Toast.LENGTH_SHORT).show();
            }
        }
	
}

3.2 Message 复用

获取 Message 大概有如下几种方式:

代码语言:javascript复制
Message message1 = myHandler.obtainMessage(); 		   //通过 Handler 实例获取Message message2 = Message.obtain();   			  //通过 Message 获取Message message3 = new Message();  				 //直接创建新的 Message 实例

通过查看源码可知,Handler.obtainMessage() 方法也是调用了 Message.obtain() 方法。

为了节省开销,我们在使用的时候尽量复用 Message,使用前两种方式进行创建。

4. 问题汇总

1.Handler 能够更新UI线程。 2.一个线程可以有多个Handler,我们new Handler的时候并不是创建了线程,而是创建了一个接收者和发送者。 3.一个线程仅有一个Looper。 4.主线程创建的Handler 和子线程创建的Handler有什么区别? ActivityThread中的main已经针对Looper进行了prepar操作,我们只用直接创建Handler就可以了。 而在子线程中创建Handler需要我们调用Looper.prepare()进行初始化Looper,然后再调用Lppper.loop()让Looper进行循环运作下去。 5.Handler是如何确保线程安全的?因为Handler发送消息和取消消息都进行了synchronize修饰。 6.Handelr的消息延时准确么?并不准确,因为线程上的加锁操作,时间并不能完全准确。 7.Looper一直循环处理会不会导致应 用卡死? 在没有消息产生的时候,Looper会被阻塞(block),并进入休眠,一旦有消息添加,那么就会进行循环处理。

0 人点赞