Handler基础用法

Handler见名识意,处理者的意思。用来处理线程的事件,有一些初学者在面试的时候直接回答是为了主线程处理事件的,这是不准确的,准确回答是用于线程间事件传递的,只要线程有一个Looper。Handler将每个线程待处理的事件一个一个的排队处理,同一时刻只会有一个事件被处理。就像产品经理将需求一条一条发给开发人员,开发人员将这些需求整理成表格,一个一个的完成开发。在Handler中,Message就相当开发人员要处理的需求。

用法

创建一个Handler

Handler有几个构造方法,按照创建的方式不同分为两种:

  1. 在一个有Looper的线程中创建:
public Handler();
public Handler(Callback callback);

这种方式创建的handler就归属于当前线程,Message由当前线程驱动执行。例如:在Activity的生命周期方法里面按照这种方式创建的handler都是归属于主线程的handler。
2. 指定一个Looper创建:

public Handler(Looper looper);
public Handler(Looper looper, Callback callback);

这种方式创建的handler归属于looper所在线程,Message由looper所在线程驱动执行。
looper的获取方式也有两种:

Looper.myLooper();
Looper.getMainLooper();

也可以通过创建单独的HandlerThread线程来获取其Looper,这也是创建非UI线程handler的最常用的方式。

HandlerThread handlerThread = new HandlerThread("AsyncThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());

使用Handler处理Message

上面说明了如何创建handler,接下来说明如何使用Handler处理Message或任务。处理Message包含形式:

1. 继承Handler

通过继承一个Handler并实现handleMessage(Message msg):

  class CusHandler extends Handler{
    public void handleMessage(Message message){
      //处理message
    }
  }

这种方式是一种较为常见的使用方式。

2. 使用Callback

通过继承的方式需要新建一个class,还要一种更灵活的方式,如前面创建handler所列举的构造方法中传入Callback的方式:

Handler handler = new Handler(new Handler.Callback() {
  @Override
  public boolean handleMessage(Message msg) {
    return false;
  }
});

基本和继承类似,都是有一个handleMessage的方法,不同的地方是这个方法有个boolean类型的返回值,而通过继承的方式是没有的。这是因为Callback的消息处理的优先级高于继承方式的优先级。也就是说,如果一个Handler同时有Callback有继承了handleMessage,那么Callback先处理,如果返回了false以后,再交给继承后重载的handlerMessage进行处理:

  class CusHandler extends Handler{

    public CusHandler() {
      super();
    }
    
    public CusHandler(Callback callback){
      super(callback);
    }
    
    public void handleMessage(Message message){
      //位置1:处理message
    }
  }
  
  CusHandler mCusHandler = new CusHandler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message message) {
      //位置2:处理message
      return false;
    }
  });

这也就意味着上面代码中位置2处理了message,如果返回false,位置1还是能够收到这个message,除非位置2返回true。

3. 使用post的方式执行Runnable,这个Message方式有所不同。

handler.post(new Runnable() {
  @Override
  public void run() {
    //在handler所属线程执行任务    
   }
});

这种方式直接把一个Runnable对象派发到handler所在线程执行,这种方式handleMessage是收不到消息的。这种方式十分方便,如果handleMessage适合处理对状态敏感的消息,这种方式就更加纯粹只注重线程间的消息传递了,例如:

//任何View
View.post(new Runnable() {
  @Override
  public void run() {
     //在UI线程中执行。 
  }
});

//在Activity中
runOnUiThread(new Runnable() {
  @Override
  public void run() {
        //在UI线程中执行。
   }
});

不需要创建一个UI线程的Handler就可以方便的把事件派发的UI线程去执行。
post的方式还有一些其它的用法:

  1. 普通方式。
public final boolean post(Runnable r)

这种方式使用是最常用的。
2. 定时方式。这里定时是设定时间的意思,只执行一次,而不是定时循环执行。

public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)

这种方式使用较少,uptimeMillis是一个从开机开始的一个绝对时间。
3. 延时方式。

public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postDelayed(Runnable r, Object token, long delayMillis)

这种方式可以用于任务的延时执行,token是用来取消任务的。

Message

Message是一个Parcelable对象,代表一个消息。包含的主要属性:

/** 消息标识 **/
public int what;
/** 参数1 **/
public int arg1;
/** 参数2 **/
public int arg2;
/** 附加参数 **/
public Object obj;

参数1和2可以用于放置一些简单的整形参数,Object可以防止任意对象(意味可以是非序列化的),这个在实际开发中非常有用的。

发送消息

向一个handler发送消息,就是线程间消息传递的一个实现形式。其实前面已经介绍过一种传递形式:handler.post。因此这里只说明非post的方式.
使用handler发送消息有两种形式:

  1. 空消息。所谓空消息,就是不需要关注Message的arg1,arg2,obj三个参数的消息,只需要一个消息标识what.
private static final int MSG_UPDATE_DATA = 1;
handler.sendEmptyMessage(MSG_UPDATE_DATA);
  1. 实体消息。这种方式需要构建一个Message对象。
private static final int MSG_UPDATE_DATA = 1;
Message msg = handler.obtainMessage();
msg.what = MSG_UPDATE_DATA;
handler.sendMessage(msg);

构建一个Message对象有多种方式:

  1. 直接new一个:
Message msg = new Message();
msg.what = MSG_UPDATE_DATA;
  1. 通过Handler.obtainMessage获取:
public final Message obtainMessage();
public final Message obtainMessage(int what);
public final Message obtainMessage(int what, Object obj);
public final Message obtainMessage(int what, int arg1, int arg2);
public final Message obtainMessage(int what, int arg1, int arg2, Object obj);

推荐使用这种方式,因为Message对象可以被复用。
Handler发送消息还有一些重载的形式,在前面介绍Handler.post方式的时候已有说明,列举如下:

public final boolean sendEmptyMessageDelayed(int what, long delayMillis);
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis);
public final boolean sendMessageDelayed(Message msg, long delayMillis);
public boolean sendMessageAtTime(Message msg, long uptimeMillis);

这些重载方法,延时发送消息是最常用的一种。

猜你喜欢

转载自blog.csdn.net/xDong66/article/details/85050499