Handler&HandlerThread

参考

Handler理解

  1. Handler一般用于进行线程间通讯,一般是子线程向主线程发送数据变动,更新UI操作。
  2. Handler的消息回调接收是是跟你创建Handler的线程绑定的,即你在那个线程创建的Handler,其不管在那个线程发送消息,最后回调的方法实现都是在你创建Handler的线程里完成。
  3. Handler跟Thread没有关系,其内部不能做耗时操作,但是可以发送延迟消息… …

    Handler机制

  • Message:消息,由MessageQueue统一队列,交给Handler处理。
  • MessageQueue:消息队列,用来存放Handler发送过来的Message,并且按照先入先出的规则执行。
  • Handler:处理者,负责发送和处理Message.
  • Looper:死循环,不断从MessageQueue中获取Message并执行。

    Looper

  1. Handler的创建时该线程中必须含有Looper对象。
  2. 在程序启动时,系统会先加载ActivityThread这个类,该类在main方法中会生成Looper对象:Looper.prepareMainLooper(),并随之创建消息队列,然后会调用Looper.loop()进行队列中的消息循环,故MainThread中可以直接创建Handler对象,发送消息。
  3. 非主线程是不自带Looper的,如果在子线程中进行Handler的创建需要自己调用Looper.prepare()创建Looper对象,不然会报java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()异常。注意:调用之前需要判断该线程是否有Looper对象,通过: Loopper.myLooper()来判断,不然会报java.lang.RuntimeException: Only one Looper may be created per thread异常。
  4. 获取主线程的Looper对象:Looper.getMainLooper()

    Handler-Message&Runable

  • sendMessage():一般用于线程间消息传递
  • post(new Runnable):其并不是开启一个Thread,只是单纯的发送一个Null的消息,回调会在Runnable的实现run()方法只执行,一般会结合HandlerThread来使用。

    子线程创建Handler对象(子线程需要借助Looper处理)

  • 方式一:
public class MyHandlerThread extends Thread {
public static final String TAG = "MyHT";

public Handler mHandler = null;

@Override
public void run() {
    Log.d(TAG, "进入Thread的run");
    Looper.prepare();//looper创建
    mHandler = new Handler(Looper.myLooper()){
        @Override
        public void handleMessage(Message msg){
            Log.d(TAG, "获得了message");
            super.handleMessage(msg);
        }
    };
    Looper.loop();//因开始无限while(true)死循环,下边的代码不会再执行,mHandler.getLooper().quit(),可以结束Looper.loop循环
    ... ...
    //主线程的所有操作都在Looper循环体内部执行,故不会出现这种情况
}
}
  • 方式二(HandlerThread:为创建子线程Looper做了安全封装):

    //在MainThread中创建,HandlerThread其实就是在创建个带有Looper对象的子线程  
    //也不能这样说:其实就是创建了个Looper对象,只是在子线程中创建的Looper对象、、、之所以创建还不是因为Handler需要在子线程中使用
    //Handler handler =new Handler();//其实内部参数是需要传入一个Looper对象的
    
HandlerThread handlerThr=new HandlerThread("HandlerThread");
      handlerThr.start();//开启线程
      Looper looper = handlerThr.getLooper();
      Handler handler=new Handler(looper, new Handler.Callback() {
          @Override
          public boolean handleMessage(Message msg) {
              //该Handler是在子线程中创建的--所以其handlerMessage()回调仍然在子线程中--回调线程是个创建Handler的线程在一起
              //故这个回调里也不能更新UI
              //需要handler.sendMessage();才能走改回调

              //因为其已经创建过Looper.prepare()<--->Looper.loop(),顾Toast可以show;
              Toast.makeText(Main2Activity.this, "异步回调", Toast.LENGTH_SHORT).show();
              //Only the original thread that created a view hierarchy can touch its views
              //btnHandlerThread.setText("thread");
              return false;
          }
      });//该Handler就是在子线程中生命的Handler---并且 你不需要Looper.prepare();Looper.loop(),HandlerThread内部已经创建了Looper对象;
      .........  // UI操作
      .........
      .........
      if(handler!=null) {
          handler.post(new Runnable() {
              @Override
              public void run() {
                ///这个是主线程回调不是子线程-可以更新UI,,message.callBack=runable;\跟普通View.post(new Runable{})不知道有啥区别
                btnHandlerThread.setText("main-thread");
                Toast.makeText(Main2Activity.this,"异步请求",Toast.LENGTH_SHORT).show();
              }
          });
      }

Destory取消队列循环

  • sendMessage()方式进行消息传递:handler.removeCallBacksAndMessages(null)
  • post(runnable)方式:handler.removeCallBacks(runnable);

Handler 创建会持有外部类对象,造成内存泄漏

详解 Handler 内存泄露的原因