Handler机制:
是一个消息传递机制,作用是将子线程需要的UI操作,传递到UI线程执行,保证线程安全。
image.png相关类介绍
- Message:线程间通讯的数据单元。
MessageQueue:消息队列,特点先进先出。存储Handler发送过来的消息(Message)
-
Handler:是一个消息处理器,将消息传递给消息队列,然后再由对应线程从消息队列中逐个取出数据,并执行
-
Looper:消息循环器,循环取出消息(Message),将取出的消息分发给对应的处理者(Handler)。
特点: -
一个Handler只能拥有一个Looper。
-
一个Looper可以绑定多个Handler
public Handler(Callback callback, boolean async) {
...
//关联Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//关联MessageQueue
mQueue = mLooper.mQueue;
...
}
在Handler的构造方法中,会关联Looper和MessageQueue(Looper的构造函数中会创建自己的MessageQueue)
源码分析
默认情况,消息队列只有一个,就是主线程的消息队列。这个线程由ActivityThread.main方法中创建,调用Looper.prepareMainLooper()创建,执行Looper.loop()来启动消息循环。
public static void main(String[] args) {
Looper.prepareMainLooper();
// 1.创建主线程Looper
ActivityThread thread = new ActivityThread();
// 2. 创建主线程
Looper.loop();
// 3. 开启消息循环
}
//设置和获取Looper,Looper保存在ThreadLocal中
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//设置Looper,只能调用一次
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper的构造函数中会创建自己的MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//获取Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
可以看到Looper存储在ThreadLocal,这就实现了线程安全。Looper可以对应多个Handler
/**
* 源码分析: Looper.loop()
* 作用:消息循环,即从消息队列中获取消息、分发消息到Handler
* 特别注意:
* a. 主线程的消息循环不允许退出,即无限循环
* b. 子线程的消息循环允许退出:调用消息队列MessageQueue的quit()
*/
public static void loop() {
...// 仅贴出关键代码
// 1. 获取当前Looper的消息队列
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// myLooper()作用:返回sThreadLocal存储的Looper实例;若me为null 则抛出异常
// 即loop()执行前必须执行prepare(),从而创建1个Looper实例
final MessageQueue queue = me.mQueue;
// 获取Looper实例中的消息队列对象(MessageQueue)
// 2. 消息循环(通过for循环)
for (;;) {
// 2.1 从消息队列中取出消息
Message msg = queue.next();
if (msg == null) {
return;
}
// next():取出消息队列里的消息
// 若取出的消息为空,则线程阻塞
// 2.2 派发消息到对应的Handler
msg.target.dispatchMessage(msg);
// 把消息Message派发给消息对象msg的target属性
// target属性实际是1个handler对象
// 3. 释放消息占据的资源
msg.recycle();
}
}
loop()是一个消息无限循环,不断从消息队列获取消息,将消息派发到对应的Handler
public final class Message implements Parcelable {
Handler target;
Runnable callback;
Message next;
}
/** dispatchMessage(msg)
* 定义:属于处理者类(Handler)中的方法
* 作用:派发消息到对应的Handler实例 & 根据传入的msg作出对应的操作
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
... // 创建Handler实例时复写
}
dispatchMessage派发消息最终会调用HandlerMessage或者run方法处理
- 当调用Handler.post时msg.callback != null,会走run方法
- 当Message.obtain方法里设置时msg.callback != null,会走run方法
- 当Handler初始化时传入Callbackh时mCallback != null,会走mCallback.handleMessage(msg)方法
- 当前面两者都没有,直接调用sendMessage时,会走handleMessage(msg) 方法
demo
public class HandlerActivity extends AppCompatActivity {
@BindView(R.id.content_tv)
TextView mContentTv;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
mContentTv.setText((CharSequence) msg.obj);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
ButterKnife.bind(this);
}
@OnClick({R.id.post, R.id.obtain, R.id.Handler_Callback_is_null, R.id.Handler_Callback_is_not_null})
public void onClick(View view) {
switch (view.getId()) {
//当调用Handler.post时msg.callback != null,会走run方法
case R.id.post:
new Thread() {
@Override
public void run() {
super.run();
mHandler.post(new Runnable() {
@Override
public void run() {
mContentTv.setText("post");
}
});
}
}.start();
break;
//当Message.obtain方法里设置时msg.callback != null,会走run方法
case R.id.obtain:
new Thread() {
@Override
public void run() {
super.run();
Message message = Message.obtain(mHandler, new Runnable() {
@Override
public void run() {
mContentTv.setText("obtain");
}
});
mHandler.sendMessage(message);
}
}.start();
break;
//当Handler初始化时传入Callback时mCallback != null,会走mCallback.handleMessage(msg)方法
case R.id.Handler_Callback_is_null:
new Thread() {
@Override
public void run() {
super.run();
Message msg = Message.obtain();
msg.what = 1; // 消息标识
msg.obj = "Handler_Callback_is_null"; // 消息内存存放
mHandler.sendMessage(msg);
}
}.start();
break;
//当前面两者都没有,直接调用sendMessage时,会走handleMessage(msg) 方法
case R.id.Handler_Callback_is_not_null:
final Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == 2) {
mContentTv.setText((CharSequence) msg.obj);
}
return true;
}
});
new Thread() {
@Override
public void run() {
super.run();
Message msg = Message.obtain();
msg.what = 2; // 消息标识
msg.obj = "Handler_Callback_is_not_null"; // 消息内存存放
handler.sendMessage(msg);
}
}.start();
break;
}
}
}
为什么可以直接post呢,因为post(Runnable r)会将Runnable包装成Message对象,并将Runnable对象设置给Message对象的callback,最好将Message对象插入消息队列中去。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//将消息插入MessageQueue
return enqueueMessage(queue, msg, uptimeMillis);
}
Handler机制流程图
image.png问题
1、为什么不new Message()而采用Message.obtain()?
因为Message内部维护了1个Message池,用于Message消息对象的复用,使用obtain()则是直接从池内获取,避免内存new Message重新分配内存。
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();
}
2、Handler可以在子线程创建吗?
通常Handler必须在主线程创建,因为Handler机制的主要作用是更新UI。当然也可以创建在子线程,那么就得自己手动去prepare和loop。
new Thread(){
@Override
public void run() {
super.run();
//创建当前线程的Looper,并绑定到ThreadLocal中
Looper.prepare();
//创建Handler,关联Looper和MessageQueue
Handler handler = new Handler();
//启动消息循环
Looper.loop();
}
}.start();
3、Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
loop虽然是死循环,但是如果messagequeue里面没有消息的话,会休眠在native层那个nativePollonce方法
4、如何避免不当导致的内存泄漏
问题根源: 非静态匿名内部类持有外部类引用
1、静态Handler内部类, 如果在handMessage方法里需要用到上下文, 进行弱化
public class NoLeakActivity extends AppCompatActivity {
private NoLeakHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new NoLeakHandler(this);
Message message = Message.obtain();
mHandler.sendMessageDelayed(message,10*60*1000);
}
private static class NoLeakHandler extends Handler{
private WeakReference<NoLeakActivity> mActivity;
public NoLeakHandler(NoLeakActivity activity){
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}
但是为什么为static类型就会解决这个问题呢?
因为在java中所有非静态的对象都会持有当前类的强引用,而静态对象则只会持有当前类的弱引用。
声明为静态后,handler将会持有一个Activity的弱引用,而弱引用会很容易被gc回收,这样就能解决Activity结束后,gc却无法回收的情况。
2、Handler内部自带的remove方法
学习参考:
https://www.jianshu.com/p/b4d745c7ff7a
https://www.zhihu.com/question/34652589/answer/90344494?from=profile_answer_card
Android开发进阶从小工到专家
网友评论