Handler消息传递机制
程序员文章站
2022-07-14 15:12:47
...
Handler机制的由来
Android的消息传递机制是另一种形式的“事件处理”,这种机制主要是为了解决多线程问题————Android只允许UI线程修改UI组件,这会导致子线程无法修改界面组件的属性。
但实际上在开发中,经常需要在新线程周期性的改变UI组件,这时需要借助Handler的消息机制。
Handler类
主要有两个作用:
- 在新线程中发送消息
Handler handler;
//1.有消息内容时
Message msg = new Message();
msg.what = 0x123;//消息代号
msg.obj = num.toString();//消息内容
handler.sendMessage(msg);//有消息内容时调用
//2.也可以使用Bundle传递消息内容
Bundle bundle = new Bundle();
bundle.putInt("num",123);
Message message = new Message();
message.what = 0x123;//消息代号
message.setData(bundle);
handler.sendMessage(message);
//3.无消息内容时
handler.sendEmptyMessage(0x234);//无消息内容时调用
- 在主线程中获取,处理消息
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {//1.判断是哪个个代号的消息
msg.obj.toString();//2.获取消息传递的内容
int num = msg.getData.getInt("num");//3.获取使用Bundle传递的内容
//4.事物处理(可处理UI组件)
}
}
};
Handler,Loop与MessageQueue
- Message:Handler接收和处理的消息对象
- Looper:每个线程只能有一个Looper。loop方法负责读取MessageQueue中的消息,读取消息后交给发送该消息的Handler进行处理。
- MessageQueue:消息队列,先进先出的方式管理Message。创建Looper对象时,同时创建MessageQueue对象。由Looper负责管理,即使用Handler机制处理消息时,当前线程必须有一个Looper对象。
- UI线程:自动初始化Looper对象,直接处理即可。
- 子线程:调用Looper.prepare()方法即可。
示例1:自动播放图片
布局界面一个ImageView即可。
public class ImageActivity extends AppCompatActivity {
Handler handler;
ImageView imageView;
public static int[] imageIds = new int[]
{
R.drawable.bomb5, R.drawable.bomb6, R.drawable.bomb7
, R.drawable.bomb8, R.drawable.bomb9, R.drawable.bomb10
, R.drawable.bomb11, R.drawable.bomb12, R.drawable.bomb13
, R.drawable.bomb14, R.drawable.bomb15, R.drawable.bomb16
};
int current = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_images);
imageView = (ImageView) findViewById(R.id.img);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x234) {//接收对应消息的代码
imageView.setImageResource(imageIds[current++ % imageIds.length]);
}
}
};
//计时器,周期性执行指定任务
new Timer().schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0x234);//发送无内容的消息代号
}
}, 0, 1200);//指定播放延时
}
}
模拟器运行以上代码,会循环每隔1.2秒改变一次图片。
示例2:模拟耗时任务改变UI组件
子线程执行耗时任务
public class PrimeNum {
public static void primeNum(final Handler handler, final int n) {
class myThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(2000);//增加耗时2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
List<Integer> num = new ArrayList<>();
//计算质数
outer:
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i != 2 && i % j == 0) {
continue outer;
}
}
num.add(i);
}
Message msg = new Message();
msg.what = 0x123;//消息代号
msg.obj = num.toString();//消息内容
handler.sendMessage(msg);//发送有内容的消息
}
}
new myThread().start();
}
}
Activity
xml一个TextView显示质数即可。
public class MainActivity extends AppCompatActivity{
private TextView text;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {//接收指定代号的消息
text.setText(msg.obj.toString());//改变UI
}
}
};
PrimeNum.primeNum(handler, 10000);//执行耗时任务
}
}
执行以上代码会在子线程运行2秒后,计算质数,返回将计算的结果显示在TextView。