关于线程的looper问题
looper的定义
looper是为了管理messagequeue存在的,把messagequeue的数据放到handle的request执行
子线程使用looper
1.Looper.prepare(); //目的生成一个和当前线程对应的looper,只能调用一次,否则会抛出异常,可以看一下源码
2.创建Handler handleMessage
3.Looper.loop(); //开始循环处理信息
代码
public class MainActivity extends AppCompatActivity {
private static final int PRE = 0;
private static final int NOW = 1;
Handler handler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("CHAO", "onCreate" + getMainLooper().toString());
new Thread(()->{
while(true) {
Looper.prepare();
handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case PRE:
Log.d("CHAO", "handleMessage PRE thread = " + getLooper().toString());
break;
case NOW:
Log.d("CHAO", "handleMessage NOW thread = " + getLooper().toString());
break;
default:
Log.d("CHAO", "handleMessage xx");
break;
}
}
};
Looper.loop();
}
}).start();
handler.obtainMessage(PRE).sendToTarget();
}
}
深层看一下,Looper.prepare();创建looper
第二步创建handler把在当前线程创建的线程和looper对应
第三步Looper.loop();,开启循环内部看一下:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
有一个for循环,queue.next();queue进去,找到next
for (;;) {
在这里面轮询处理信息,当有符合信息返回到Looper里,looper再处理
来个小图
关于myLooper()和getMainLooper()
简单说:在android的一个进程中,会有一个ThreadLocal<Looper> sThreadLocal,这个sThreadLocal维护一个looper对应一个线程的map表
主线程也就是ui线程的looper(),android已经为我们生成,对应主线程
当我们创建一个Handler的时候,源码里面会有
mLooper = Looper.myLooper();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
所以当Hander定义在主线程中,是不需要额外设置hander的,也就是说looper将要执行的handleMessage是运行在主线程
调用Looper.myLooper(),打印出的是主线程
那么如果我们在子线程呢?
直接调用Looper.myLooper(),一下子就会报出异常
因为android源码:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
中间总结一下
关于looper,hander执行的地方就是looper绑定的线程,所以呢,你想让你的handleMessage运行在哪就运行在哪,只要传给不同的线程里面的looper就好
handerThread
android为我们提供的类,不需要我们创建线程然后开启looper繁琐的工具,其实我们想要的就是让handleMessage在线程中执行
HandlerThread内部也是继承Thread的,实现了run的方法,在run里面进行了Looper.prepare();Looper.loop();
所以你看这不是和我们刚刚做的一样么
试验一下,注意的是匹配的looper是在构造的时候进行赋值的,所以我们要在创建Hander的时候赋值looper
HandlerThread handlerThread = new HandlerThread("HandlerThread");
if(handlerThread.isAlive()) {
handlerThread.start();
handler = new Handler(handlerThread.getLooper()) {
public void handleMessage(Message msg) {
switch (msg.what) {
case PRE:
Log.d("CHAO", "handleMessage PRE thread = " + getLooper().toString());
break;
case NOW:
Log.d("CHAO", "handleMessage NOW thread = " + getLooper().toString());
break;
default:
Log.d("CHAO", "handleMessage xx");
break;
}
}
};
}
so easy!
一个圆,圆内是你会的,圆外是你不知道的。而当圆越大,你知道的越多,不知道的也越多了


浙公网安备 33010602011771号