出于性能优化的考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity的UI组件。
当一个程序第一次启动时,Activity会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键操作、用户触摸屏幕的事件及屏幕绘制事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
Android的消息传递机制是另一种形式的“事件处理”,这种机制主要为解决Android应用的多线程问题---Android平台只允许UI线程修改Activity里的UI组件,这就会导致新启动的线程无法动态改变界面组件的属性值。但实际在开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程周期性的改变界面组件的属性值,这就需要借助于Handler的消息传递机制。
Handler类主要作用有两个:
---在新启动的线程中发送消息;
---在主线程中获取、处理消息。
上面的说法看上去很简单,似乎只分成两步:在新线程中发送消息,然后再主线程中获取并处理消息即可。但过程中涉及一个问题,新启动的线程何时发送消息?主线程又何时处理消息?时机如何控制?
为了解决处理消息问题,只能通过回调的方式来实现---重写Handler类的handleMessage()方法。 当新启动的线程发送消息时,消息会发送到与之关联的MessageQueue,而Handler会不断从MessageQueue中获取并处理消息--这将导致Handler中处理消息的方法被回调。
计算质数实例:
package com.example.calprime;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String DATA_NUM = "num";
private static final String RESULT_KEY = "result_key";
EditText editText;
MyThread myThread;
TextView result;
class MyThread extends Thread {
public Handler mHandler;
@Override
public void run() {
// super.run();
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x110) {
int num = msg.getData().getInt(DATA_NUM);
List<Integer> nums = new ArrayList<>();
//计算从2开始到num的所有质数
for (int i = 2; i <= num; i++) {
//用i除以从2开始,到i的平方根的所有数
boolean isadd = true;
for (int j = 2; j <= Math.sqrt(i); j++) {
//如果可以整除,则不是质数
if (i != 2 && i % j == 0) {
isadd = false;
continue;
}
}
if (isadd) {
nums.add(i);
}
}
//Toast显示
Toast.makeText(MainActivity.this, nums.toString(), Toast.LENGTH_LONG).show();
Message message = new Message();
message.what = 0x111;
Bundle bundle = new Bundle();
bundle.putString(RESULT_KEY, nums.toString());
message.setData(bundle);
mUiHandler.sendMessage(message);
}
}
};
Looper.loop();
}
}
Handler mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x111) {
result.setText(msg.getData().getString(RESULT_KEY));
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.edit);
result = findViewById(R.id.result);
myThread = new MyThread();
myThread.start();
}
public void cal(View view) {
Message message = new Message();
message.what = 0x110;
Bundle bundle = new Bundle();
bundle.putInt(DATA_NUM, Integer.parseInt(editText.getText().toString()));
message.setData(bundle);
myThread.mHandler.sendMessage(message);
}
}
运行结果: