之前其实我在别的博客中说过这个了,大家可以进行参考。
Android Handler消息发送,子线程发消息执行UI操作
Android防止Handler造成内存泄漏的方法
不过这里我要进行一下比较全面一些的总结,因为关于Hanlder和Message的配合真的是很多的。我们就从主子线程消息传递来展开说说。
主线程和分线程之间传递消息的步骤主要有4个。
1.在主线程中构造一个Handler对象,并启动分线程
这里关于分线程的启动我就不说了,因为根据实际情况的不同我们会有不同的子线程。同时,我们不会为了消息转发去创建子线程,往往是因为子线程要更新UI界面所以要消息转发。因此,当我们开发需要消息转发时,我默认为你已经有一个子线程了,可能是因为要耗时操作启动的子线程,也可能是网络请求回调回来在子线程中。
我们说一下关于Handler对象的创建,其实很简单,我们可以直接创建一个对象
就像这样
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
也可以创建一个内部类继承Handler,就像这样
private class MineHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
}
不管哪种,都实现了我们创建Handler的目的。之前我有一篇讲Hander的提过一种防止内存泄漏的Hander。之所以Handler会造成内存泄漏,是因为咱们Handler中的代码执行是依托消息的,也就是Handler本身有一堆代码,根据接收到的消息排队执行对应的代码。但是如果我们的引用没有了 ,比如Activity销毁了,但是Handler是不知道的,它还在执行,所以当用到了上下文的引用,就会产生内存泄漏的问题。 其实一方面可以使用我当时写的那种方法,把上下文引用存入WeakReference中,或者直接在引用的时候判断是否为空我认为也是可以的。
2.在分线程中构造一个Message对象的消息包。
当我们要从子线程转发消息到主线程时,就要构造一个Message对象。我一般就比较粗暴了,直接这样
Message message = new Message();
优雅一点的有这样
Message message = Message.obtain();
更优雅一点还可以这样
Message message = handler.obtainMessage();
总之作用是一样的,我们就是要创建一个Message对象。大家认识各种方法就好,万一小伙伴有这么写的认识就行。自己写的时候用自己习惯的。我就比较喜欢粗暴一些的。
接着说说Message类的主要参数。
我们Message可以通过如下参数携带一些信息。
- what:整型的消息标识,用于标识本次消息的唯一编号。
- arg1:整型数,可存放消息的处理结果。
- arg2:整型数,可存放消息的处理代码。
- obj:Object类型,可存放返回消息的数据结构。
- replyTo:Messenger类型,回应信使,在跨进程通信中使用,多线程通信用不着。
3.在分线程中通过Handler对象将Message消息发出去
处理器Handler的消息发送操作主要是各类send方法。下面总结一下(注意:Handler不是只有send类方法,还有很多别的方法,只是咱们这里只说和消息有关的)
- obtainMessage:获取当前消息的对象。
- sendMessage:立即发送消息。
- sendMessageDelayed:延迟一段时间后发送消息。
- sendMessageAtTime:在指定时间点发送消息。
- sendEmptyMessage:立即发送空消息。
- sendEmptyMessageDelayed:延迟一段时间后发送空消息。
- sendEmptyMessageAtTime:在指定时间发送空消息。
- removeMessages:从消息队列中根据指定标识移除对应的消息。
- hasMessage:判断消息队列中是否存在指定标识的消息。
4.主线程中的Handler对象处理接收到的消息
主线程处理分线程发出的消息需要实现Handler对象的handleMessage方法,根据Message消息的具体内容分别进行相应处理。注意,因为handleMessage方法处于主线程(UI线程)中,所以该方法内部可以直接操作界面元素。