Handler详解(上)

一.Handler简单使用

 

1.Handler最常规的用法是 在UI线程接收消息,在子线程发送消息

 

代码

public class HandlerActivity extends AppCompatActivity {

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_WHAT:
                    int num1 = msg.arg1;
                    int num2 = msg.arg2;
                    String string = (String) msg.obj;
                    String result = "主线程 接收 子线程发送的Message num1: " + num1 + "  num2: " + num2 + "  result: " + string;
                    mTextView.setText(result);
                    Log.d("HandlerActivity", result);
                    break;
            }
        }
    };

    private TextView mTextView;
    private final int MSG_WHAT = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        //模拟子线程发送消息
        mTextView = findViewById(R.id.activity_handler_textview);
        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message msg = Message.obtain();
                        msg.what = MSG_WHAT;
                        msg.arg1 = 1;
                        msg.arg2 = 2;
                        msg.obj = "字符串";
                        handler.sendMessage(msg);
                    }
                }).start();
            }
        });
    }
}

 

结果

D/HandlerActivity: 主线程 接收 子线程发送的Message num1: 1  num2: 2  result: 字符串

 

 

 

2.Handler还可以的用法是 有时候需要在子线程创建运行在主线程中的Handler 

 

代码

private void createNewThreadHandler() {
     new Thread(new Runnable() {
         @Override
         public void run() {
             new Handler().postDelayed(new Runnable() {
                  @Override
                  public void run() {
                      Log.d("TAG", "延时200毫秒执行的代码...");
                  }
             }, 200);
          }
     }).start();
}

 

上述代码在大部分手机会报错,比如 魅族测试机报错信息

即 Can't create handler inside thread that has not called Looper.prepare()

 

修改后的代码

private void createNewThreadHandler() {
    new Thread(new Runnable() {
         @Override
         public void run() {
             new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                 @Override
                 public void run() {
                     Log.d("TAG", "延时200毫秒执行的代码...");
                 }
             }, 200);
         }
     }).start();
}

 

结果

TAG: 延时200毫秒执行的代码...

 

报错原因

非主线程中默认没有开启Looper,而Handler对象必须绑定Looper对象,需要调用Looper.prepare()来给线程创建一个消息循环。需要调用Looper.loop()来使消息循环起作用。当然在new Handler对象时,在构造方法中传入Looper.getMainLooper()也可以解决报错的问题。具体原因下面讲解。

 

 

 

 

 

 

 

二.Handler常用方法

 

1.发消息:sendMessage(msg)

代码

Message msg = Message.obtain();
msg.what = MSG_WHAT;
msg.arg1 = 1;
msg.arg2 = 2;
msg.obj = "字符串";
handler.sendMessage(msg);

 

源码

/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

 

内部调用

内部调用 sendMessageDelayed(msg, 0)方法,即调用延时的方法,只不过延时0。相当于不延时。

 

 

2.延时XXX发消息:sendMessageDelayed(msg,500)

代码

Message msg = Message.obtain();
msg.what = MSG_WHAT;
msg.arg1 = 1;
msg.arg2 = 2;
msg.obj = "字符串";
handler.sendMessageDelayed(msg,500);

 

源码

 /**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

 

内部调用

内部调用 sendMessageAtTime()方法。

 

 

3.发空消息:sendEmptyMessage(what);

代码

handler.sendEmptyMessage(MSG_WHAT);

 

源码

/**
 * Sends a Message containing only the what value.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendEmptyMessage(int what){
    return sendEmptyMessageDelayed(what, 0);
}

 

内部调用

内部调用 sendEmptyMessageDelayed(what, 0);方法,即调用延时的方法,只不过延时0。相当于不延时。

 

 

4.延时XXX发空消息:sendEmptyMessageDelayed(what, 500);

代码

handler.sendEmptyMessageDelayed(MSG_WHAT, 500);

 

源码

 /**
 * Sends a Message containing only the what value, to be delivered
 * after the specified amount of time elapses.
 * @see #sendMessageDelayed(android.os.Message, long) 
 * 
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

 

内部调用

内部调用 sendMessageDelayed()方法。

 

 

5.UI线程刷新UI方法:post(Runnable runnable)

代码

Handler.post(new Runnable() {
  @Override
  public void run() {  
               
  }
});

 

源码

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is 
 * attached. 
 *  
 * @param r The Runnable that will be executed.
 * 
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}

 

内部调用

内部调用 sendMessageDelayed(getPostMessage(r), 0);方法。

 

 

6.延时XXX毫秒UI线程刷新UI:postDelayed(Runnable runnable,long delayMillis)

代码

uiHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
                
    }
},100);

 

源码

 /**
 * Causes the Runnable r to be added to the message queue, to be run
 * after the specified amount of time elapses.
 * The runnable will be run on the thread to which this handler
 * is attached.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 *  
 * @param r The Runnable that will be executed.
 * @param delayMillis The delay (in milliseconds) until the Runnable
 *        will be executed.
 *        
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the Runnable will be processed --
 *         if the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

 

内部调用

内部调用 sendMessageDelayed(getPostMessage(r), delayMillis);方法。

 

 

总结

<1> Handler几个常用的方法,比如发送消息/延时XXX毫秒发送消息,比如发送空消息/延时XXX毫秒发送空消息,比如UI线程刷新UI/延时XXX毫秒UI线程刷新UI等等。

<2> 使用Handler的post方法或者postDelayed方法。没有主动创建Message对象。但是上述讲的这两个方法会分别调用sendMessageDelayed(getPostMessage(r), 0);和sendMessageDelayed(getPostMessage(r), delayMillis);方法。在这两个方法中 系统默认获取Message对象

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

即 获取消息池中的Message对象。

<3> 其实上述几个方法,最终都会走到Handler的sendMessageAtTime(Message msg, long uptimeMillis)方法。

<4> 流程图

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值