我们在开发中经常用到的在子线程中执行耗时任务,然后通过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();
- }
- }
布局文件
- "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>