关于线程的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!

posted @ 2020-06-01 17:11  make_wheels  阅读(766)  评论(0)    收藏  举报