目录
写在前面
时间截止到2022年9月2日。(为什么说明时间,因为安卓在不断地更新不断地完善,今天能跑的代码放到明天不一定能正常运行,因为安卓完善可能会因为性能原因舍弃掉某些功能的实现或者是以新的算法来优化原来的功能)
基础概念
在其他线程中更新UI界面被安卓认为是不安全的,安卓是不允许的,UI线程(主线程)当然可以更新UI界面,于是可以通过其他线程发数据(通信内容)给UI线程让其帮忙更新数据。
什么是handler?
handler主要接受子进程的发送的数据,并用此数据配合主线程更新UI.
以我个人使用而言,见字面意思,它是一个消息处理类。使用必须重写其中的handleMessage(Message msg)方法,一个线程如果获得了另一个线程的handler对象,则能通过另一个线程的handler.sendxxx发送信息。
Message msg 的常用属性有
.obj (Object类型) 可以是任意类型的数据,取出来后再强制转换即可。
.what(int类型)我个人使用用于判断由那个控件产生的事件引起的通信。
目前handler的空参构造已经被废弃,可以通过指定的looper来进行构造。
#例如在主线程中构造handler
private Handler mHandler= new Handler(Looper.getMainLooper()) {
@Override
//重写handleMessage方法,根据msg中what的值判断是否执行后续操作
public void handleMessage(Message msg) {
if (msg.what == 0) {
i++;
runt.setText(String.valueOf(i));
}
}
};
什么是looper?
正如上面的handler可以发送消息,Message(消息)由一个消息队列进行管理,而消息队列又是由一个looper进行管理的,Looper负责管理线程的消息队列和消息循环,在主线程中自动创建了一个looper,而其他子线程则需要自己手动创建。
在主线程中,通过Loop.getMainLooper可以获得主进程的Looper对象。
在子进程中,先Looper.prepare()创建消息队列,再通过Loop.myLooper得到当前线程的Looper对象,最后通过Looper.loop进入消息循环。
总结:
handler与looper是唯一映射的关系;
一个handler只能拥有一个looper;
一个looper只能和一个线程相照应,同时一个looper也对应着唯一一个MessageQueue。
一个looper却可以拥有多个handler (因为handler可以通过指定looper来创建)
比如在子线程中创建handler
class Ctrl extends Thread {
public Handler Chandler;
public Looper Clooper =Looper.myLooper();
public void run(){
Looper.prepare();
Chandler=new Handler(Clooper){
@Override
public void handleMessage(Message msg) {
if(msg.what== 0){
Log.e(TAG, "子线程收到消息" );
}
}
};
Looper.loop();
}
}
什么是消息队列(MessageQueue)?
它是由Looper这个管理类所维护的,handler分发一个消息,消息队列中的消息加1,Looper.loop不断从队头取出消息供handler处理。
在子线程中使用子线程中的数据更新UI线程
使用方法
MainActivity.this.runOnUiThread(new Runnable() // 重写其中run方法
比如
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
runt.setText(time+"s");
tl.setText(TempLimit);
hl.setText(HumiLimit);
ll.setText(LsLimit);
isc.setText(_isc);
temp.setText(_temp);
humi.setText(_humi);
ls.setText(_ls);
if(cons)state.setText("已连接");
else {
state.setText("断开连接");
state.setTextColor(R.color.red);
}
}
});
主线程与子线程通信实例(程序代码)
子线程获取主线程handler发送数据给主线程。
在UI中的oncreate中
mhandler=new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
if(msg.what==0){
Log.e(TAG, "主线程收到消息:"+(String) msg.obj );
}
}
};
在子线程中
class Ctrl extends Thread {
Message msg;
public void run(){
while (true){
try {
Thread.sleep(1000);
msg=new Message();
msg.what=0;
msg.obj="hello";
mhandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
效果:
主线程发信息给子线程
值得注意的是,子线程的handler需要在子线程中创建looper,通过
Looper.prepare();
创建。
具体代码
package com.example.yuezhenhao;
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.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import javax.security.auth.Subject;
//
public class UIshow extends AppCompatActivity {
private String TAG="UIshow";
private Handler subandler; //子线程handler对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uishow);
Ctrl ctrlthread=new Ctrl();
ctrlthread.start();
new Timer().schedule(new TimerTask() {
@SuppressLint("ResourceAsColor")
@Override
public void run() {
if(subandler != null) subandler.sendEmptyMessage(0);
}},0,1000);
}
///子线程
class Ctrl extends Thread {
public Handler Chandler;
public void run(){
Looper.prepare();
Chandler=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
if(msg.what== 0){
Log.e(TAG, "子线程收到消息" );
}
}
};
if(subandler == null) {
subandler= Chandler;
}
Looper.loop();
}
}
}
效果: