一.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> 流程图