前言
相信大家初学Android一定写过这样的代码:
1、在onCreate方法中:先发送网络请求,将得到的数据赋给一个String对象,然后接着就用一个TextView来显示这个数据
2、后来搞懂了不能在主线程发送网络请求,那好,在子线程当中发送网路请求得到数据以后,直接在子线程中更新UI
那当然了,这两种情况都是行不通的,当时还特别的纳闷怎么回事。。。
Handler机制的理解
相信大家对Handler不陌生吧,在Android开发时,Handler是很常用的,那我们好好的回顾一下
在Android开发中,规定只有UI线程,也就是主线程能进行UI更新的操作,比如说网络请求这种耗时操作就只能在子线程当中进行了,那我们很多时候需要把从网络请求来的数据显示到UI界面上,那这就需要用到异步了,那么Handler是其中一种比较常用的方式,那我们说一下他们之间的关系吧:
主线程:应用程序第一次启动时,就会开启一条主线程,处理UI更新
子线程:我们人为开启的线程,执行耗时操作比如说网络请求等
Message:线程间通讯的数据单元,存放数据
MessageQueue:存储Handler发送来的消息
Handler:意为处理者,发送消息,处理更新UI的操作
Looper:意为循环器,MessageQueue和Handler的媒介
大体说一下整个流程吧:
在启动一个Activity时,也就是启动了一个主线程的时候,
会默认自动创建一个Looper和MessageQueue对象,然后Looper自动进入到消息循环,
然后我们创建了Handler,Handler会自动绑定主线程的Looper和MessageQueue对象,
当我们在子线程中发送网络请求后得到了数据,将数据放入Message中,然后通过Handler的sendMessage方法发送到MessageQueue当中
Looper循环取出MessageQueue中的消息,然后将消息分发给Handler
最后handler根据分发过来的Message中的内容进行UI操作
看了这么多一定云里雾里的,我给大家做个比喻吧,来一张图:
我们要做一个大型的画展,现场作画
舞台(主线程)只负责展示大家的画作(更新UI),
幕后作画(子线程)是画家进行创作过程(网络请求下载等耗时操作),
画作(Message)是作画完成后由工作人员打包好的,
用于暂时存放画作的箱子(MessageQueue),
工作人员团队(Handler)
观察员(looper)
好了,画展开始举办了,首先我们看到的是舞台(启动了主线程),观察员和放画的箱子第一个先就位了(自动创建Looper和MessageQueue对象),观察员自画展开始就一直在时刻关注箱子里有没有画作(实际并不是这样进行无脑操作),然后画家们开始作画了(子线程发送网络请求),谁完成了画作(得到了数据),就把作品交给工作人员,工作人员发送到箱子内(handler .sendMessage),然后观察员看到箱子内有作品了,把作品取出来安排给工作人员让他把作品送到舞台上面,展示给大家(在handlerMessage中进行UI操作)。
注意,一个画展只有一个观察员,但是观察员手底下可以有好几个工作人员团队。
一个线程只能绑定一个Looper,但可以有多个Handler。
Handler的使用
1、布局文件
2、新建Handler的子类,采用内部类的方式(我们还可以采用匿名内部类)
class Mhandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
textView.setText(msg.obj.toString());
break;
default:
break;
}
}
}
3、创建Handler对象
private TextView textView;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.text_view);
handler = new Mhandler();
sendRequest();
}
4、模拟发送网络请求
private void sendRequest(){
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//创建一个Message实例,
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "得到了某网站返回的数据,并更新了UI";
handler.sendMessage(msg);
}
}.start();
}
运行结果:
Handler有两种方式,上面用的是handler.sendMessage()的方式
还有一种handler.post(),就是用法不一样,要在子线程new一个Runnable,不用重写handlerMessage()方法
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过psot()发送,传入1个Runnable对象
mHandler.post(new Runnable() {
@Override
public void run() {
// 指定操作UI内容
mTextView.setText("得到了某网站返回的数据,并更新了UI");
}
});
}
}.start();
小Demo地址:https://github.com/pengboboer/HandlerTest
总结
Handler的理解和用法大致就是这样,可能我写的比较粗浅,但是也够初学者理解Handler机制,自己也记录下来,大家多多包涵。当然,上面这个例子是会存在内存泄漏风险的,非静态内部类和匿名内部类会默认持有外部类的引用。
我发现一个大神写的不错,分析Handler源码的,篇幅比较大,大家如果想深入了解可以看一下:
https://blog.csdn.net/carson_ho/article/details/80388560
好了,就是这样。晚安~