[TOC]
什么是Handler
?
Handler
主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理。
执行如下代码,启动Activity
后立马退出,销毁该Activity
,如果没有onDestroy()
方法中的处理,3秒后仍然能启动第二个Activity
,引起内存泄漏。由此可见onDestroy()
方法中的处理对避免内存泄漏是十分重要的!
private Handler handler1 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
startActivity(new Intent(MainActivity.this, PersonalActivity.class));
return false;
}
});
private void test() {
new Thread(new Runnable() {
@Override
public void run() {
//1、Handler内存泄漏测试(假象)
SystemClock.sleep(3000); //销毁Activity
message.what = 3;
if(handler1 != null) {
handler1.sendMessage(message); //跳转到第二个界面
}
//handler1.sendMessageDelayed(message, 3000);
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy --> ");
handler1.removeMessages(3);
handler1 = null;
}
从Handler
源码中可以看出Looper.myLooper();
方法拿不到子线程的looper
,所以报异常。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//这里获得的looper为空
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
不过可以通过如下两种方式在子线程中创建Handler
:
//方式一
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
}
}
handler.sendEmptyMessage(1);
Looper.loop();
}
}).start();
//方式二
new Thread(new Runnable() {
@Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
}
}
handler.sendEmptyMessage(1);
}
}).start();
这句话是错误的,Veiw
的setText()
方法虽然有线程检查的机制,但是当其运行地足够快,速度超过线程检查机制的执行时是可以在子线程执行成功的。
TextView
--> setText()
--> checkForRelayout()
--> requestLayout()
--> mParent.requestLayout()
--> ViewRootImpl.requestLayout()
--> checkThread()
:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
两种Handler
的写法如下:
private Handler handler1 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
startActivity(new Intent(MainActivity.this, PersonalActivity.class));
return false;
}
});
//这是谷歌备胎的API,不推荐使用
private Handler handler2 = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
textView.setText(msg.obj.toString());
}
};
ActivityThread
--> main()
--> Looper.loop()
--> msg.target.dispatchMessage(msg)
--> Handler.dispatchMessage()
:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
由上面源码可知优先使用handler1
,实在没有办法了才使用handler2
,handler2
是谷歌备胎的API
,不推荐使用。
@Test
public void test() {
//创建本地线程(主线程)
final ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
@Nullable
@Override
protected String initialValue() {
//重写初始化方法,默认返回null,如果ThreadLocalMap拿不到值再调用初始化方法
return "天涯路";
}
};
//从ThreadLocalMap中获取string值,key是主线程
System.out.println("主线程threadLocal: " + threadLocal.get());
//------------------------thread-0
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//从ThreadLocalMap中获取key: thread-0的值?没有,拿不到值再调用初始化方法
String value1 = threadLocal.get();
System.out.println(Thread.currentThread().getName() + ": " + value1); //天涯路
//ThreadLocalMap存入:key:thread-0 value:"走天涯"
threadLocal.set("走天涯");
String value2 = threadLocal.get();
System.out.println(Thread.currentThread().getName() + " set >> : " + value2); //走天涯
//使用完成建议remove(),避免大量无意义的内存占用
threadLocal.remove();
}
});
thread.start();
//------------------------thread-1
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//从ThreadLocalMap中获取key: thread-1的值?没有,拿不到值再调用初始化方法
String value1 = threadLocal.get();
System.out.println(Thread.currentThread().getName() + ": " + value1); //天涯路
//ThreadLocalMap存入:key:thread-1 value:"断肠人"
threadLocal.set("断肠人");
String value2 = threadLocal.get();
System.out.println(Thread.currentThread().getName() + " set >> : " + value2); //断肠人
//使用完成建议remove(),避免大量无意义的内存占用
threadLocal.remove();
}
});
thread1.start();
}
public final boolean sendEmptyMessage(int what);
public final boolean sendEmptyMessageDelayed(int what, long delayMillis);
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis);
public final boolean sendMessageDelayed(Message msg, long uptimeMillis);
public boolean sendMessageAtTime(Message msg, long uptimeMillis);
public final boolean sendMessageAtFrontOfQueue(Message msg);
// ↓
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Looper.loop()
-->handler.dispatchMessage()
public void dispatchMessage(@NonNull 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();
}
- 每个
Thead
对应一个Looper
;- 每个
Looper
只对应一个MessageQueue
;- 每个
MessageQueue
中有N
个Message
;- 每个
Message
最多指定一个Handler
来处理事件,一个线程可以有多个handler
,但一个handler
只能绑定一个线程;Looper
是属于某一个线程的,一个Looper
只对应一个MessageQueue
,判断这个handleMessage()
方法在哪个线程上运行,就看这个Handler
的Looper
对象是在哪个线程,就在对应的线程上执行。
Handler
流程形象示意图:
是的
因为在Looper.next()
开启死循环的时候,一旦需要等待时或还没有执行到任务的时候,会调用NDK
里面的JNI
方法,释放当前时间片,这样就不会引发ANR
异常了。
具体来说是利用Linux
的epoll
+pipe
机制,使得主线程在阻塞的时候,让出CPU
资源,同时等待新的消息。当我们对系统进行操作(包括滑动和点击)的时候,系统就会给主线程发送消息,这时候就会唤醒主线程(执行onCreate
,onResume
等方法),当处理完这个消息,就会再次进入阻塞状态,这样系统就能做到随时响应用户的操作。
如果在Handler
构造方法里面new Looper
,就无法保证Looper
唯一,只有用Looper.prepare()
才能保证唯一性,具体可以看prepare()
方法。
因为一个线程只有绑定一个Looper
,所以在Looper
构造方法里面初始化就可以保证mQueue
也是唯一的Thread
对应一个Looper
对应一个mQueue
。
在Java
测试单元下
public class ActivityThread {
@Test
public void main() {
//创建全局唯一的,主线程Looper对象,以及MessageQueue消息队列对象
Looper.prepare();
//模拟Activity中创建Handler对象
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println(msg.obj.toString( ));
}
};
//消费消息,回调方法(接口方法)
//子线程发送消息
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.obj = "hello world";
handler.sendMessage(message);
}
}).start();
//轮询,取出消息
Looper.loop();
}
}
//消息对象
public class Message {
//标识
public int what;
//消息内容
public Object obj;
//Handler对象
public Handler target;
public Message() {
}
public Message(Object obj) {
this.obj = obj;
}
//模拟
@NonNull
@Override
public String toString() {
return obj.toString();
}
}
//消息队列
public class MessageQueue {
//阻塞队列
BlockingQueue<Message> blockingQueue = new ArrayBlockingQueue<>(50);
//将Message消息对象存入阻塞队列中
public void enqueueMessage(Message message) {
try {
blockingQueue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//从消息队列中取出消息
public Message next() {
try {
return blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
public class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
public MessageQueue mQueue;
private Looper() {
mQueue = new MessageQueue();
}
public static void prepare() {
//主线程只有唯一一个Looper对象
if(sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//应用启动时,初始化赋值
sThreadLocal.set(new Looper());
}
public static Looper myLooper() {
return sThreadLocal.get();
}
//轮询,提取消息
public static void loop() {
//从全局ThreadLocalMap中获取唯一Looper对象
Looper me = myLooper();
//从Looper对象中获取全局唯一消息队列MessageQueue对象
final MessageQueue queue = me.mQueue;
Message resultMessage;
//从消息队列中取消息
while (true) {
Message msg = queue.next();
if(msg != null && msg.target != null) {
msg.target.dispatchMessage(msg);
}
}
}
}
public class Handler {
private Looper mLooper;
private MessageQueue mQueue;
public Handler() {
mLooper = Looper.myLooper();
if(mLooper == null) {
throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
// 给开发者提供的开放API,用于重写和回调监听
public void handleMessage(Message msg) {
}
public void sendMessage(Message message) {
//将消息放入消息队列中
enqueueMessage(message);
}
private void enqueueMessage(Message message) {
//赋值当前handler
message.target = this;
//使用mQueue,将消息放入
mQueue.enqueueMessage(message);
}
public void dispatchMessage(Message msg) {
handleMessage(msg);
}
}