在Android中,主线程负责管理与UI相关的事件;在自己创建的子线程中,不能对UI组件进行操作。
例如,如下代码在单击按钮时创建新线程,这时改变文本框的显示文本会crash:
public class MainActivity extends AppCompatActivity {
protected void onCreate() {
...
button.setonClickListener(new View.onClickListener( {
public void onClick(View v) {
Thread thread = new Thread(new Runnable()) {
public void run() {
textView.setText("xxxxxxx");
}
});
thread.start();
}
});
}
}
因此,Android引入Handler消息机制,来实现在新创建的线程中操作UI。
2 Handler与Looper,MessageQueue的关系关于详细的实现原理请参考老罗的讲解:
Android应用程序的消息处理机制(MessageQueue,Looper,Handler)_u012906122的专栏-CSDN博客
Handler类:
(1)在任意线程中发送消息
通过调用Handler的sendMessage()将消息发送到MessageQueue中。
(2)在主线程中获取并处理消息
覆写Handler类的handleMessage()方法。当Looper循环到该Message时,会回调Handler的handleMessage()处理消息。
Looper类:
管理MessageQueue。每个线程只能有一个Looper,loop()方法负责读取MessageQueue中的消息,读取到消息后把消息传给Handler进行处理。
Message类:
(1)Message:通过Handler发送和处理的消息对象。
(2)MessageQueue:FIFO消息队列。
Handler与Looper,MessageQueue的关系如下:
一个线程对应一个Looper对象,一个Looper对象对应一个MessageQueue,MessageQueue用于存放Message。
Handler发送Message给Looper管理的MessageQueue,Looper又从MessageQueue中取出消息,给Handler处理。
因此,如果要在程序中使用Handler,必须在当前线程中有一个Looper对象。线程中的Looper对象有以下两种创建方式:
(1)UI主线程中,系统默认已经初始化一个Looper对象了,程序可以直接创建Handler,发送和处理消息。
(2)子线程中,需要手动创建一个Looper对象,并通过loop()启动Looper。
[1]调用Looper的prepare()来为当前线程创建Looper对象,同时创建MessageQueue。
[2]创建Handler实例,覆写handleMessage()方法。
[3]调用Looper的loop()方法启动Looper。
注意:一个线程中,只有一个Looper和MessageQueue,但可以有多个Handler。
3 使用Handler实现进度条倒计时发送和处理消息都是在主线程
MainActivity.java
public class MainActivity extends Activity {
public final static String TAG = "ProgressBar";
final int TIME = 20;
final int TIMER_MSG = 0x001;
private ProgressBar timer;
private int mProgressStatus = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer = (ProgressBar) findViewById(R.id.timer);
handler.sendEmptyMessage(TIMER_MSG); //发送消息,启动进度条
Log.d(TAG, "onCreate tid:" + android.os.Process.myTid());
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//当前进度大于0
if (TIME - mProgressStatus > 0) {
mProgressStatus++; //进度+1
Log.d(TAG, "handleMessage mProgressStatus:" + mProgressStatus);
Log.d(TAG, "handleMessage tid:" + android.os.Process.myTid());
timer.setProgress(TIME - mProgressStatus); //更新进度条的显示进度
handler.sendEmptyMessageDelayed(TIMER_MSG, 1000);
} else {
Toast.makeText(MainActivity.this, "时间到!", Toast.LENGTH_SHORT).show();
Log.d(TAG, "handleMessage timeout!");
}
}
};
}
GitHub - hanyuhang-hz/android-demos
4 使用Handler实现轮播广告使用Message类时注意:尽管Message类有public构造方法,但通常情况下,需要使用Message.obtain()或Handler.obtainMessage()从消息池中获得空消息对象,以节省资源。
Message对象属性描述如下:
| 属性 | 类型 | 描述 |
| arg1 | int | 存储整型数据 |
| arg2 | int | 存储整型数据 |
| obj | Object | 存储Object类型的任意对象 |
| replyTo | Messenger | 指定此Message发送到何处的Messenger |
| what | int | 指定用户自定义的消息代码 |
MainActivity.java
public class MainActivity extends Activity {
final int FLAG_MSG = 0x001;
private ViewFlipper flipper;
private Message message;
//定义图片数组
private int[] images = new int[]{R.drawable.img1, R.drawable.img2, R.drawable.img3,
R.drawable.img4, R.drawable.img5, R.drawable.img6, R.drawable.img7, R.drawable.img8};
private Animation[] animation = new Animation[2]; //定义动画数组,为ViewFlipper指定切换动画
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
flipper = (ViewFlipper) findViewById(R.id.viewFlipper);
for (int i = 0; i < images.length; i++) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(images[i]); //将遍历的图片保存在ImageView中
flipper.addView(imageView); //加载图片
}
animation[0] = AnimationUtils.loadAnimation(this, R.anim.slide_in_right); //右侧平移进入动画
animation[1] = AnimationUtils.loadAnimation(this, R.anim.slide_out_left); //左侧平移退出动画
flipper.setInAnimation(animation[0]); //为flipper设置图片进入动画效果
flipper.setOutAnimation(animation[1]); //为flipper设置图片退出动画效果
message=Message.obtain();
message.what=FLAG_MSG;
handler.sendMessage(message);
}
Handler handler = new Handler() { //创建android.os.Handler对象
@Override
public void handleMessage(Message msg) {
if (msg.what == FLAG_MSG) {
flipper.showPrevious();
}
message=handler.obtainMessage(FLAG_MSG); //获取要发送的消息
handler.sendMessageDelayed(message, 3000);
}
};
}
GitHub - hanyuhang-hz/android-demos
子线程中,需要手动创建一个Looper对象,并通过loop()启动Looper。
[1]调用Looper的prepare()来为当前线程创建Looper对象,同时创建MessageQueue。
[2]创建Handler实例,覆写handleMessage()方法。
[3]调用Looper的loop()方法启动Looper。
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("Looper", "onCreate tid:" + android.os.Process.myTid());
LooperThread thread=new LooperThread(); //创建一个线程
thread.start(); //开启线程
}
}
LooperThread.java
public class LooperThread extends Thread {
public Handler handler;
@Override
public void run() {
super.run();
Looper.prepare(); //初始化Looper对象
//实例化一个Handler对象
handler = new Handler() {
public void handleMessage(Message msg) {
Log.i("Looper", "handle msg:" + String.valueOf(msg.what));
Log.d("Looper", "handleMessage tid:" + android.os.Process.myTid());
}
};
Message m=handler.obtainMessage(); //获取一个消息
m.what=0x7; //设置Message的what属性的值
handler.sendMessage(m); //发送消息
Log.i("Looper", "send msg:" + String.valueOf(m.what));
Log.d("Looper", "sendMessage tid:" + android.os.Process.myTid());
Looper.loop(); //启动Looper
}
}
https://github.com/hanyuhang-hz/android-demos
注意:Looper.loop()之后的代码不会被执行,因为loop()函数是一个循环。只有调用了Handler.getLooper().quit()后,loop()方法才会终止,后面的代码才会运行。



