我们在开发中经常用到的在子线程中执行耗时任务,然后通过Handler到主线程中更新UI。我们对它都很熟悉,今天再来复习一下这个Handler。下面几种方式是今天要复习的
(1)单向的子线程与子线程交互:即由一个子线程向另一个子线程发送消息;
需要先创建一个新的子线程,然后在子线程内创建Handler,来接收另一个子线程发来的消息。在子线程中创建Handler必须要先获取Looper,否则程序则会崩溃,并且会报错误:Can't create handler inside thread that has not called Looper.prepare()。Handler消息机制源码详解参考这篇文章:https://www.jianshu.com/p/750e3706c467
/*
(1)子线程与子线程交互(单向)。
创建一个新的子线程
*/
class MyThread1 extends Thread{
public Handler mHandler1;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler1 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(1)子线程中使用Handler向另一个子线程发消息(单向)");
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
之后由一个线程向这个新线程发送消息
private MyThread1 myThread1;
myThread1 = new MyThread1();
myThread1.start();
new Thread(){
@Override
public void run() {
super.run();
myThread1.mHandler1.sendEmptyMessage(0);
}
}.start();
(2)两个子线程互发消息(双向):需要创建两个线程并相互发送消息
/*
(2)两个子线程互发消息(双向)
即创建两个线程,并在一个线程发送消息到另一个线程处理
*/
class MyThread21 extends Thread{
public Handler mHandler21;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler21 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 20:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("收到");
//收到消息,使用MyThread22的mHandler22向MyThread22发送消息
myThread22.mHandler22.sendEmptyMessage(22);
}
});
break;
case 21:
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
//收到MyThread22发来的消息
tv_receivedMsg.setText("(2)两个子线程互发消息(双向)\n 线程1收到MyThread22发来的消息");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
class MyThread22 extends Thread{
public Handler mHandler22;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler22 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 22:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(2)两个子线程互发消息(双向)\n 线程2收到myThread21发来的消息");
try {
Thread.sleep(2000);
//收到myThread21发来的消息,使用myThread21的mHandler21向myThread21发消息
myThread21.mHandler21.sendEmptyMessage(21);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
执行这两线程互相发送消息
private MyThread21 myThread21;
private MyThread22 myThread22;
myThread21 = new MyThread21();
myThread22 = new MyThread22();
myThread21.start();
myThread22.start();
myThread21.mHandler21.sendEmptyMessage(20);
(3)主线程发送消息到子线程:先创建一个子线程
//(3)主线程发消息到子线程
class MyThread3 extends Thread{
public Handler mHandler3;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler3 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(3)子线程收到主线程发来的消息");
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
然后由主线程向新建的子线程发送消息
private MyThread3 myThread3;
myThread3 = new MyThread3();
myThread3.start();
myThread3.mHandler3.sendEmptyMessage(0);
(4)子线程发送消息主线程:这个也是我们平时最常用的
//子线程发送消息主线程
new Thread(new Runnable() {
@Override
public void run() {
mHandler.sendEmptyMessage(4);
}
}).start();
在主线程中创建Handler来接收消息
Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 4:
tv_receivedMsg.setText("主线程收到子线程发来的消息");
break;
}
}
};
(5)附加一个handler.post的使用,可直接在run里面更新UI。Handler的sendMessage和post的区别可参考这篇文章:https://www.jianshu.com/p/43d6cd7b06f1
mHandler.post(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("handler.post通过实现Runnable接口,直接更新UI");
}
});
整个复习测试的完整源程序
public class HandlerTestActivity extends AppCompatActivity {
View viewStatus;
private Button btn_handler1,btn_handler2,btn_handler3,btn_handler4;
private Button btn_handlerPost;
private TextView tv_receivedMsg;
private MyThread1 myThread1;
private MyThread21 myThread21;
private MyThread22 myThread22;
private MyThread3 myThread3;
Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 4:
tv_receivedMsg.setText("主线程收到子线程发来的消息");
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
initView();
initData();
initListener();
}
private void initView(){
if (Build.VERSION.SDK_INT >= 21) {
View decorView =getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
//这上面是颜色
getWindow().setStatusBarColor(Color.TRANSPARENT); //也可以设置成灰色透明的,比较符合Material Design的风格
}
viewStatus = findViewById(R.id.view_status);
ViewGroup.LayoutParams layoutParams = viewStatus.getLayoutParams();
layoutParams.height = getStatusBarHeight();
btn_handler1 = findViewById(R.id.btn_handler1);
btn_handler2 = findViewById(R.id.btn_handler2);
btn_handler3 = findViewById(R.id.btn_handler3);
btn_handler4 = findViewById(R.id.btn_handler4);
btn_handlerPost = findViewById(R.id.btn_handlerPost);
tv_receivedMsg = findViewById(R.id.tv_receivedMsg);
}
private void initData(){
/**
* (1)子线程与子线程交互(单向)。
*/
myThread1 = new MyThread1();
myThread1.start();
/**
* (2)两个子线程互发消息(双向)
*/
myThread21 = new MyThread21();
myThread22 = new MyThread22();
myThread21.start();
myThread22.start();
/**
* (3)主线程发送消息到子线程。
*/
myThread3 = new MyThread3();
myThread3.start();
}
private void initListener(){
//子线程中使用Handler向另一个子线程发消息(单向)
btn_handler1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public void run() {
super.run();
myThread1.mHandler1.sendEmptyMessage(0);
}
}.start();
}
});
btn_handler2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myThread21.mHandler21.sendEmptyMessage(20);
}
});
btn_handler3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myThread3.mHandler3.sendEmptyMessage(0);
}
});
btn_handler4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//子线程发送消息主线程
new Thread(new Runnable() {
@Override
public void run() {
mHandler.sendEmptyMessage(4);
}
}).start();
}
});
//Handler.post的使用
btn_handlerPost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("handler.post通过实现Runnable接口,直接更新UI");
}
});
}
});
}
/*
(1)子线程与子线程交互(单向)。
创建一个新的子线程
*/
class MyThread1 extends Thread{
public Handler mHandler1;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler1 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(1)子线程中使用Handler向另一个子线程发消息(单向)");
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
/*
(2)两个子线程互发消息(双向)
即创建两个线程,并在一个线程发送消息到另一个线程处理
*/
class MyThread21 extends Thread{
public Handler mHandler21;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler21 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 20:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("收到");
//收到消息,使用MyThread22的mHandler22向MyThread22发送消息
myThread22.mHandler22.sendEmptyMessage(22);
}
});
break;
case 21:
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
//收到MyThread22发来的消息
tv_receivedMsg.setText("(2)两个子线程互发消息(双向)\n 线程1收到MyThread22发来的消息");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
class MyThread22 extends Thread{
public Handler mHandler22;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler22 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 22:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(2)两个子线程互发消息(双向)\n 线程2收到myThread21发来的消息");
try {
Thread.sleep(2000);
//收到myThread21发来的消息,使用myThread21的mHandler21向myThread21发消息
myThread21.mHandler21.sendEmptyMessage(21);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
//(3)主线程发消息到子线程
class MyThread3 extends Thread{
public Handler mHandler3;
@Override
public void run() {
super.run();
//1.实例化当前线程的Looper,每个线程只能有一个Looper实例。
Looper.prepare();
//2.创建Handler
mHandler3 = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_receivedMsg.setText("(3)子线程收到主线程发来的消息");
}
});
break;
}
}
};
//3.开启Looper循环接收消息
Looper.loop();
}
}
@Override
protected void onDestroy() {
if (null != myThread1.mHandler1){
myThread1.mHandler1.removeCallbacksAndMessages(null);
}
if (null != myThread21.mHandler21){
myThread21.mHandler21.removeCallbacksAndMessages(null);
}
if (null != myThread22.mHandler22){
myThread22.mHandler22.removeCallbacksAndMessages(null);
}
if (null != myThread3.mHandler3){
myThread3.mHandler3.removeCallbacksAndMessages(null);
}
super.onDestroy();
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:orientation="vertical">
<View
android:id="@+id/view_status"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#01012A" />
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="Handler的交互场景"
android:background="@color/colorPrimary"
android:gravity="center"
android:textSize="18dp"
android:textColor="@color/white"/>
<Button
android:id="@+id/btn_handler1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(1)子线程与子线程交互(单向)"/>
<Button
android:id="@+id/btn_handler2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="(2)两个子线程互发消息(双向)"/>
<Button
android:id="@+id/btn_handler3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="(3)主线程发送消息到子线程"/>
<Button
android:id="@+id/btn_handler4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="(4)子线程发送消息主线程"/>
<Button
android:id="@+id/btn_handlerPost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="(5)handlerPost方法"
android:textAllCaps="false"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="接收消息:"
android:textSize="18dp"
android:textColor="@color/white"/>
<TextView
android:id="@+id/tv_receivedMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:textColor="@color/blueP"/>
</LinearLayout>