Handler是什么
handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理机制,我们可以发消息,也可以通过它处理消息
原理(解析异步消息处理机制)
Message | Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。 |
Handler | Handler主要用于发送和处理消息的,发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过处理后,最终会传递到Handler的handlerMessage()方法中 |
MessageQueue | 消息队列,用于存放所有通过Handler发送的消息。每个线程只有一个MessageQueue对象 |
Looper | Looper是每个线程的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将他取出,并传递到Handler的handlerMessage()方法中。每个线程也只会有一个Looper对象 |
处理过程
- 在主线程创建Handler对象。
- 重写
handlerMessage()
方法。 - 当子线程需要UI操作时,就创建一个Message对象,并通过Handler将这条消息发出去。
- 这条消息被添加到MessageQueue中等待处理,最后分发回handlerMessage中。
- 由于Handler是在主线程创建的,所以此时handlerMessage()方法也在主线程中运行,于是就可以进行UI操作了。
举例
利用Handler修改子线程UI,这里简单演示修改TextView的文字。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView show;
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//接收,判断,处理消息
switch (msg.what) {
case UPDATE_TEXT:
show.setText("更改UI");
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//一个Textview,修改文字来达到模拟更改界面UI的效果
show = (TextView) findViewById(R.id.tv_show);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_show:
//开启线程(这里是模拟在线程里要修改UI的情况)
new Thread(new Runnable() {
@Override
public void run() {
//定义一个Message,可以发送给Handler
Message myMessage = new Message();
//用户定义的消息代码,以便接收者能够识别该消息的内容。
myMessage.what = UPDATE_TEXT;
//把myMessage放到消息队列的末尾,它将在handleMessage(Message)中接收
handler.sendMessage(myMessage);
}
});
default:
break;
}
}
}
给message设置数据
如果你需要发送数据,那么可以往message里放一个Bundle类型的数据,如下
//设置数据
Bundle bundle = new Bundle();
bundle.putInt("data1", 1);
bundle.putString("data2", "数据二");
message.setData(bundle);
在handleMessage中将数据取出
//取出数据
int data1 = msg.getData().getInt("data1");
String data2 = msg.getData().getString("data2");
sendEmptyMessage()
如果你不需要设置数据,其实不用像上面例子那样麻烦,使用sendEmptyMessage()
方法可以一行解决,相当于直接发个msg.what给handler了,可以做个对比。
//方法1用三行代码
Message myMessage = new Message();
myMessage.what = UPDATE_TEXT;
handler.sendMessage(myMessage);
//方法2只用一行代码
handler.sendEmptyMessage(UPDATE_TEXT)
Handler+TimerTask(3个步骤)
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.e(TAG, "收到信息");
}
super.handleMessage(msg);
}
};
Timer timer=new Timer();
TimerTask task=new TimerTask(){
@Override
public void run() {
Message message = new Message();
message.what=1;
handler.sendMessage(message);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//延迟5秒发送消息
timer.schedule(task,5000);
}
Handler+Runnable(3个步骤)
Handler handler = new Handler();
Runnable mRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, "开始工作");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//执行任务
handler.post(mRunnable);
}
简单的循环定时器
每隔一秒执行一次work()
函数
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
Handler handler = new Handler();
Runnable mRunnable = new Runnable() {
@Override
public void run() {
work();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一次调用work函数
work();
}
//定义work函数
public void work() {
handler.postDelayed(mRunnable, 1000);
Log.e(TAG, "收到信息");
}
}
HandlerThread
关于HandlerThread的写了另外一篇,感兴趣的可以看下,把耗时的操作放到子线程中去,比如下载文件。而主线程通过收到子线程的各种动态,比如子线程开始下载、子线程下载完成来修改主页面的UI,可以弹个框提示,或者修改TextView文字等等…传送~传送