该文主要用于自我总结,提炼。语句未经斟酌,存在冗余重复等情况。各人客官可移步个人主页右下方的《原创技术博客》文集,里面是对外发布的一些技术博客。(咳咳,如果用的是移动设备,简书好像还没支持,只能自己找。。)
当然也可继续阅读,如若有些地方生涩难懂。那。。那就给我发私信,我整理一下。( ●▽● )
判断所在的线程是不是主线程
可以使用
if (Looper.getMainLooper()==Looper.myLooper()){
//是主线程
}else {
//不是主线程
}
这里的Looper.getMainLooper()得到的就是主线程的Looper实例。这没有什么好说的。因为主线程的Looper在UI线程创建的时候(app启动的时候)就调用了
Looper.prepare();//初始化Looper对象
Looper.loop();//启动Looper
所以说,主线程的looper实例肯定是有的,并且已经运行了。
那么工作线程(异步线程)呢?不好意思,异步线程初始化时并没有绑定一个looper实例:
Threads by default do not have a message loop associated with them. Of course, the method works
所以如果一个工作线程没有绑定looper,那么Looper.myLooper()返回的结果将是null。如果想绑定一个looper线程,并让它运行,就需要:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();//初始化Looper对象
Looper.loop();//启动Looper
//做一些线程的其他逻辑
}
}).start();
我们看到上面Looper.myLooper(); Looper.prepare();Looper.loop();Looper的静态方法中并没有传入指定线程,但是最终得到的就是所在线程的looper或操作所在线程的looper。这是怎么做到的呢?
这是因为在Looper内部维护了一个ThreadLocal:
public class Looper {
static final ThreadLocal<looper> sThreadLocal = new ThreadLocal<looper>();
public static void prepare() {
prepare(true);
}
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));
}
...
}
我们知道,在某一个线程调用sThreadLocal.get()时,得到的是该线程的数据的looper。前面的提到的Looper.prepare()用来在本线程生成一个looper实例在这里的源码中也体现出来了。就是new 一个looper,然后放到ThreadLocal中。并且保证了一个线程只能有一个looper实例。
todo
- 在一个线程调用ThreadLocal的get/set方法,为什么得到的就是当前thread的值?
- Thread currentThread = Thread.currentThread();这样能得到当前线程的信息。
- 然后根据当前线程的信息去ThreadLocal中拿线程对应的值。可以将ThreadLocal理解为一块存储区,将这一大块存储区分割为多块小的存储区,每一个线程拥有一块属于自己的存储区,那么对自己的存储区操作就不会影响其他线程。对于ThreadLocal,则每一小块存储区中就保存了与特定线程关联的Looper。
- looper的looper()方法做了什么工作?