首先是三个组件的源码解析
Handler消息源码流程分析
https://www.jianshu.com/p/6f25729ef62a
HandlerThread线程间通信 源码解析
https://www.jianshu.com/p/69c826c8a87d
IntentService源码解析
https://www.jianshu.com/p/83d9a3e09f0a
简单一点,
IntentService本质是一个Service(所以要清单注册)
在OnCreate阶段,初始化了一个HandlerThread(本质是一个Thread),一个ServiceHandler(本质是一个Handler),还附带了一个Intent。
通过HandlerThread创建的Looper*,把这个Looper绑定到ServiceHandler
此时就可以做到子线程处理Intent
在OnStart阶段,ServiceHandler把msg发送出去(其实就是那个Intent啦)
私有类ServiceHandler里的handleMessage方法处理这些intent。
IntentService的好处:在启动Service做操作后不用自己管理生命周期,在hanldeIntent之后就主动stopSelf。
而处理耗时操作又交给了HandlerThread这样的子线程。
那为什么不是交给Thread线程呢?
这里就得说 HandlerThread的好处,其自己在初始化的时候(实际是run方法)创建了一个Looper*,这个Looper是子线程的Looper。
把子线程Looper绑定到Handler上,这个Handler就成了子线程的Handler,专门用来处理类似联网的耗时操作(不可操作界面)
如果直接在Thread里new Handler,实际上是会报错的。
当然也有处理方案
new Thread() {
public void run() {
Looper.prepare();
new Handler().post(runnable);//在子线程中直接去new 一个handler
Looper.loop();//这种情况下,Runnable对象是运行在子线程
}
}.start();
http://www.cnblogs.com/jingmo0319/p/5730963.html
梳理一下
handler
thread
threadLocal
looper
messageQueue
的对应关系
private Looper looper;//其实是主线程的looper
private Handler handler1 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("ceshi--handler1---" + msg.what + "---" + Thread.currentThread().getName());
}
};
private Handler handler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("ceshi---handler2---" + msg.what + "---" + Thread.currentThread().getName());
}
};
Thread thread1 = new Thread() {
@Override
public void run() {
super.run();
Handler handler6 = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("ceshi--handler6---" + msg.what + "---" + Thread.currentThread().getName());
}
};
Message msg6 = new Message();
msg6.what = 6;
handler6.sendMessage(msg6);
Message msg1 = new Message();
msg1.what = 1;
handler1.sendMessage(msg1);
Message msg2 = new Message();
msg2.what = 2;
handler2.sendMessage(msg2);
System.out.println("ceshi-thread1---" + Thread.currentThread().getName());
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
super.run();
Message msg3 = new Message();
msg3.what = 3;
handler1.sendMessage(msg3);
Message msg4 = new Message();
msg4.what = 4;
handler2.sendMessage(msg4);
System.out.println("ceshi-thread2---" + Thread.currentThread().getName());
Looper.prepare();//这个才是子线程的looper
Handler handler5 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("ceshi--handler5--" + msg.what + "---" + Thread.currentThread().getName());
}
};
Message msg5 = new Message();
msg5.what = 5;
handler5.sendMessage(msg5);
Looper.loop();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
looper = getMainLooper();
System.out.println("ceshi---mainTh--"+Thread.currentThread().getName());
thread1.start();
thread2.start();
}
输出结果
System.out: ceshi---mainTh--main
System.out: ceshi-thread2---Thread-3
System.out: ceshi-thread1---Thread-2
System.out: ceshi--handler5--5---Thread-3
System.out: ceshi--handler1---3---main
System.out: ceshi---handler2---4---main
System.out: ceshi--handler6---6---main
System.out: ceshi--handler1---1---main
System.out: ceshi---handler2---2---main
Thread和Handler的关系
一个Thread里同一时间可以持有n个Handler
这里是mainThread持有handler1,handler2,和handler6!
但是Handler同一时间,能有持几个Thread?1个。
简单的问:同一handler发送的消息,能被几个thread接收到?
不同的thread里的handler接收消息就是各自的handleMsg方法,实际是msg.target.dispatchMsg,而msg.target就是之前那个调用sendMsg的handler,说白了就是一一对应关系。
Thread和Looper的关系
一个Thread里同一时间只能存在一个Looper
由Looper类的prepare()方法可知
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.prepare(),因为主线程在初始化的时候已经初始化了一个Looper。
代码位置在Activity类里找ActivityThread,ActivityThread的main方法
public static void main(String[] args) {
省略..
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
反过来,Looper同一时间也只能持有一个Thread
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
子线程开启,没有looper,想用handler,就得looper.prepare(),那么就会new一个looper,Looper的构造方法就绑定了当前thread。
Looper和ThreadLocal的关系
在Looper类里,还有个饿汉式初始化ThreadLocal
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal sThreadLocal = new ThreadLocal();
也就是Looper同一时间只有一个threadLocal
反过来,threadLocal.set方法实际是内部维护一个map
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
threadLocal同一时间也就只有一个Looper咯
Looper prepare的时候,
先检查 threadLocal,先get,看能不能拿到looper
再set,把looper set到threadLocal里
ThreadLocal 的get方法,很诡异
看起来是key,value,key是thread,value是looper
实际上是获取 thread里私有的threadLocal,
因为ThreadLocal.ThreadLocalMap是线程私有的。
这个ThreadLocalMap是ThreadLocal的静态内部类。
然后并不是真正的map。而是一个 Entry数组。
这个数组存的方式也很奇怪,index是threadLocal的hashCode
value是Entry。
entry的key是 ThreadLocal,value是其持有的私有对象值,这里是looper
然后,这个entry,继承的是一个WeakReference
这个能保证,weakReference里的threadLocal 就不算强引用,可以正常回收,threadlocalMap也就可以回收,这样里面的一些私有变量就可以被回收。
举个例子, userInfo放到threadLocal里,做线程私有变量,当userInfo不用了,userInfo==null,
但是threadLocal还持有userInfo(集合持有),threadLocal生命周期跟thread一起,可能这个thread就一直没释放,也就没回收,导致内部的threadLocalMap就一直保留着userInfo.
这里就可以做到,threadLocal的remove函数,会主动清理掉entry,避免集合引用导致的泄露。
ThreadLocal看看这篇的学习方法吧,挺好的
https://mp.weixin.qq.com/s/XZIf5tCU03Upscdl1mQ8qA
looper和messageQueue的关系
一一对应,不多说了。
Handler和Looper的关系
一个handler同一时间只能持有一个Looper,看构造方法就可以知道了。
但是一个Looper统一时间可以持有多个Handler
(就是mainLooper持有了handler1,handler2)
如果在子线程里这样创建handler,实际这个handler也属于主线程,也就是被mainLooper持有
Thread thread2 = new Thread() {
@Override
public void run() {
super.run();
Looper.prepare();
Handler handler5 = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("ceshi--handler5--" + msg.what + "---" + Thread.currentThread().getName());
}
};
Looper.loop();
}
};