当子线程要发送 Message 给主线程时,首先要为此子线程创建一个Handler 类对象,由Handler调用相应的方法,将需要发送的Message发送到MessageQueue(消息队列)中/当Looper 发现MessageQueu中有未处理的消息时,就会将此消息广播出去,当主线程的 Handler 接收到此 Message 时,就会调用相应的方法来处理这条信息,完成主界面的更新。
效果:
代码:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class ThreadActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_show;
private Button btn_get_message;
private Handler mainHandler,subHandler;//定义Handler对象
private static final int ToMain = 1;
private static final int ToSub = 2;
@SuppressLint("HandlerLeak")//注意这段的位置
class subThread implements Runnable {//创建子线程类
@Override
public void run() {
Looper.prepare();//初始化Looper
subHandler = new Handler(){//定义子线程的Handler对象
@Override
public void handleMessage(Message msg) {//覆写handleMessage
switch (msg.what){
case ToSub://主线程发送给子线程消息
System.out.println("Main Child Message :"+msg.obj);//打印消息
Message message = mainHandler.obtainMessage();//创建消息
message.obj = "This is a message from Sub";
message.what = ToMain;//设置主线程操作的状态码
mainHandler.handleMessage(message);//发送
break;
}
}
};
Looper.loop();//启动该线程的消息队列
}
}
@SuppressLint("HandlerLeak")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread);
tv_show = findViewById(R.id.tv_show);
btn_get_message = findViewById(R.id.btn_get_message);
mainHandler = new Handler(){//定义主线程的Handler对象
@Override
public void handleMessage(Message msg) {//消息处理
switch (msg.what){
case ToMain:
tv_show.setText("主线程接受的数据:"+msg.obj.toString());
break;
}}};
new Thread( new subThread()).start();//启动子线程
btn_get_message.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(subHandler!=null){
//判断是否已经实例化子线程Handler
Message childMsg = subHandler.obtainMessage();
childMsg.obj ="This is a Message from Main";
childMsg.what = ToSub;
subHandler.sendMessage(childMsg);//向子线程发送消息
}
}
@Override
protected void onDestroy() {
super.onDestroy();
subHandler.getLooper().quit(); //结束队列
}
}
需要注意的地方:
创建两个Handler对象,一个是主线程,一个是子线程。通过类subThread实现接口Runnale,并覆写其中的run()方法。run()方法在启动子线程时调用,也就是start()的使用会调用回调方法run()。如下面的代码:
new Thread( new subThread()).start(); new了一个Thread对象,并没给名字。参数里面同样new了一个对象,该类实现了接口Runnable,从而在调用start()方法的时候实现接口回调。
当进到页面后,先定义主线程的Handler对象,覆写里面的handleMessage()方法来接受子线程发送的消息并进行相应的处理。并通过如下方式启动子线程:
new Thread( new subThread()).start();
当点击按钮后,会向子线程发送消息。子线程会通过覆写后的handleMessage()方法来接受和处理主线程发送的消息。在此时还会向主线程发送消息,主线程也会通过覆写后的handleMessage()方法来接受和处理子线程发送的消息。
当然,这是我自己的理解,书上是这样的:
当子线程要发送 Message 给主线程时,首先要为此子线程创建一个Handler 类对象,由Handler调用相应的方法,将需要发送的Message发送到MessageQueue(消息队列)中/当Looper 发现MessageQueu中有未处理的消息时,就会将此消息广播出去,当主线程的 Handler 接收到此 Message 时,就会调用相应的方法来处理这条信息,完成主界面的更新。
同时:子线程不能更新主线程的组件数据,否则会报错!!!
注意Message对象的获取方式:
Message message = mainHandler.obtainMessage();//创建消息
mainHandler可根据相应的Handler对象更改对应名字,尽量不要用new.