Android日记之消息机制(1)
前言
在网上看到许多的关于Android消息机制的讲解,觉的还是自己重新看书并自己写一篇来理解会更好,消息机制的内容也是在面试中最容易被问到的内容,因为消息机制的内容比较多,我会分成好几篇来进行讲解,有错误也请大家多多包涵并指出。
消息机制是什么
从一般角度来说,Android的开发机制指的就是Handler,它是Android消息机制的上层接口,我们只需要对他进行交互就好了,它也是Android开发中最经常接触的一个消息机制,Handler默认关联主线程,虽然要提供Runnable参数 ,但默认是直接调用Runnable中的run()
方法。对于一些异步的耗时操作还有最重要的更新UI这些就都需要通过Handler来进行实现,我们也就从这里开始入手。
Handler的基本使用
package com.ju.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class HandlerActivity extends AppCompatActivity {
private Button b1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//这里更新业务逻辑或者更新UI
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
b1 = findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
Message message = new Message();
//这个是标志,可以发送多个,比如arg1,arg2等等。
message.what = 1;
handler.sendMessage(message);
}
}.start();
}
});
}
}
这里先创建了一个Handler的对象,并重写了handleMessage()
的方法,这个方法就是执行主要的业务逻辑的,然后创建了一个子线程,在子线程里面创建了一个Message的对象,这个Message就是Handler要处理的对象,Message有多个字段。
public void testMessage(){
Message message = new Message();
//传入的是int类型
message.what = 1;
message.arg1 = 2;
message.arg2 = 3;
//传入的是Object类型
message.obj = null;
}
我们发现不仅是可以传入int值,其实也可以传入Object的类型,这样Handler就可以执行一些更复杂的操作了,然后在通过sendMessage()
这个方法来把消息发送出去,message对象就会传到Handler的handleMessage()
里根据字段进行具体的业务逻辑处理。注意的是Handler的handleMessage()
这时候就已经是在主线程中进行了,而不是在子线程中进行运行。这就是最基本的使用方法了。
Handler工作原理
这里我们就先不从源码开始解析(因为源码有点多= =),这里大概的讲解一下Handler的工作原理,Handler主要就是由4个部分组成:Message、Handler、MessageQueue和Looper。而Handler的运行的底层就需要有
MessageQueue和Looper来进行支撑。我们一个个来看它们的作用。
-
Meesgae
它就是Handler之间的传递的消息,是一个封装了需要传递给Handler数据的对象,也可以携带Object和int类型的消息来传递到Handler进行处理,刚刚上面也展示过了。 -
Handler
它就是用来发送和处理消息的,一般都是通过sendMessage()
和sendEmptyMessageAtTime()
来进行发送消息,担任也有其他发送消息的方法,具体有什么区别我们稍后再讲,通过Handler进行发送消息后,经过一系列的处理,就会传递到handleMessage()
里面去来进行处理。 -
MessageQueue
它是一个消息队列,是一个单链表,通过handler发送出来的消息都会传递到这个消息队列里面,然后依次的被等待处理,每一个线程只会有一个MessageQueue。 -
Looper
Handler消息机制原理,侵删
他是一个轮询器,通过Looper的loop()
方法,就会进入到一个无限的循环中,然后当MessageQueue里有一条待处理的消息,就会取出来分发到Handler的handleMessage()
方法中进行处理,每一个线程也只会有一个Looper对象。
以上总结经过Looper发送到handleMessage()
的时候,也就代表了从子线程转到了主线程,这样就可以进行UI的处理了,这里补充一句,关于UI更新还有一个方法就是runOnUiThread()
方法,它也是一个异步消息的接口封装,背后的原理其实跟上面描述的原理是一样的。
Message
发现没有,如果要进行Handler的传递,就一定需要一个Message,但是如果每次需要调用的Handler的时候就创建一个Message实例化的话,又会非常的浪费资源。其实创建Message有其它的方法。
//通过Handler取出Message
Message message1 = handler.obtainMessage();
//通过Message自带的obtain()来取出Message
Message message2 = Message.obtain();
我们这里先看第一种的源码吧
//Handler类
public final Message obtainMessage()
{
return Message.obtain(this);
}
//Message类
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
//也是第二种绑定方式的源码
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Handler类里的obtainMessage()
其实就是调用了Message的obtain()
方法,然后再去调用了Message内部类的obtain()
方法来返回Message。而第二种绑定方式就是直接调用了obtain()
就直接创建了Message,这样子的效率其实是会更高的,源码这里发现其实Message是一个链表,这里判断如果是空链表的话,就创建一个Message,然后将头链表移除掉,将头链表的下一个作为新的节点,并维护sPoolSize,sPoolSize就是节点数量,而且还加了个synchronized的锁。这样子就减少了对Message的重复利用,也不会一直创建Message对象,提高了效率。
Handler的发送
Handler的发送方法有很多,这里说几个比较常见的。
- sendMessage(Message msg)
这个也是基本的发送方式,传入Message就可以发送到Handler进行处理了。 - sendEmptyMessage(int what)
其实里面就是调用了sendEmptyMessageDelayed()
这个方法传入要识别的信息,只是这个信息是int类型的。 - sendEmptyMessageDelayed(int what, long delayMillis)
这个也是一样的,在sendEmptyMessage()
里面其实就是调用了这个sendEmptyMessageDelayed()
方法,第二个参数就是代表了消息发送的延时而已。
Handler的内存泄露
其实如果直接调用重写Handler的handlerMessage()
是有可能会引起内存泄露的,官方并不建议这样使用Handler,可以按照官方给出的解决办法的使用方法。
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
参考
- Handler消息机制之深入理解Message.obtain()
- [郭霖] 第一行代码Android(第二版)
- [任玉刚]Android开发艺术探索