Android中的消息机制指的就是Handler的运行机制,Handler是用来跨线程通信的,为了避免ANR,我们会把耗时操作放到子线程中去执行,因为子线程不能更新UI,这里就要借助到Android的消息机制也就是Handler了,Handler会把相关的UI操作切换到主线程中去执行。
注意:为什么不能在子线程中访问UI?
答:UI控件非线程安全,在多线程中并发访问可能会导致UI控件处于不可预期的状态,而不对UI控件的访问加上锁,那是因为加上锁会让UI控件变得复杂和低效,同时也会阻塞某些进程的执行。
- Handler的使用
- Handler的工作原理
一.Handler的使用
1.核心要素
(1)Message:消息,由Handler发送,包括消息ID、消息处理对象以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
(2)MessageQueue:消息队列,用来存放Handler发送过来的消息,内部由单链表的数据结构来维护数据列表,等待Looper抽取。
(3)Handler:负责消息的发送和处理,通过Handler.sendMessage()向消息池发送各种消息事件,再通过Handler.handleMessage()处理相应的事件。
(4)Looper:轮询器,通过Looper.loop()不断地从MessageQueue中抽取Message,按分发机制将消息分发给目标处理者。
2.Thread和Handler的关系
(1)Thread负责调度整个消息循环,即消息循环的执行场所。
(2)一个Thread只能有一个Looper,可以有多个Handler。
(3)Looper有一个MessageQueue,可以处理来自多个Handler的Message。即MessageQueue中有一组待处理的Message,这些Message可来自不同的Handler。
(4)Message中记录了负责发送和处理消息的Handler。
(5)Handler中有Looper和MessageQueue。
3.具体实现
(1)在主线程实例化一个Handler对象。
(2)在需要更新UI的子线程里实例化Message并填充必要的数据,通过Handler.sendMessage()发送出去。
(3)复写handleMessage()方法,对不同Message执行相关操作。
public class HandlerActivity extends AppCompatActivity {
private static class MyHandler extends Handler{
/*
* 如果直接持有外部类的强引用,可能会导致内存泄露
* 这里用软引用保存,当内存不足可以被GC回收
* */
private WeakReference<HandlerActivity> mHandlerActivity;
public MyHandler(HandlerActivity activity) {
this.mHandlerActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
String message = (String) msg.obj;
Toast.makeText(mHandlerActivity.get(),message,Toast.LENGTH_SHORT).show();
}
}
private MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
Button bt = findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.obj = "这里是子线程发送的消息";
myHandler.sendMessage(message);
}
}).start();
}
});
}
}
二.工作原理
1.工作流程
(1)Handler.sendMessage()发送消息时,会通过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息。
(2)通过Looper.loop开启循环后,不断轮询调用MessageQueue.next()。
(3)通过调用Handler.dispatchMessage()去传递消息,目标Handler收到消息后回调Handler.handleMessage()处理消息。
2.工作原理
(1)Looper:在主线程中自动创建了Looper,子线程需要手动创建.需要注意的是,无论是主线程还是子线程,Looper只能被创建一次,即一个Thread只有一个Looper.而所创建的Looper会保存在ThreadLocal中,TreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说则无法获取到数据,在这里可以通过TreadLocal获取每一个Thread的Looper.
//子线程手动创建Looper
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();//为子线程创建Looper
Handler mHandler = new Handler();
Looper.loop();//开启消息轮询
}
}).start();
注意:
a.Looper可以通过quit和quitSafely来退出,二者的区别是quit会直接退出,quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后才会安全退出.
b.loop方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法返回了null,当调用了quit和quitsafely方法,next方法就会返回null.
(2)MessageQueue:在Looper的构造函数中创建了一个MessageQueue,它主要包含两个操作,插入和读取,这两个操作分别对应的方法是enqueueMessage和next,enqueueMessage的作用是往消息队列中插入一条消息,而next的作用是从消息队列中取出一条消息并将其从消息队列中移除,它的内部是通过一个单链表的数据结构来维护消息列表,next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在那里.
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static void loop() {
...
for (;;) {//死循环
Message msg = queue.next(); // 用于提取下一条消息,当没有处理该Message的Handler时,会一直阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);//从MessageQueue中拿到Message,通过和它绑定的Handler将它发送到handleMessage处理
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
(3)Handler:主要负责消息的发送和接收过程,消息的发送可以通过post的一系列方法和send的一系列方法来实现,post的一系列方法最终是通过send的一系列方法来实现的.
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
Handler发送消息仅仅是向消息队列中插入了一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交给Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段.
下面通过一张图整体了解下Handler的运行机制(来源于android的消息机制——Handler机制)