好长时间都没有发布新的博客了,今天来写一篇关于Android中使用频率极高,但是也经常让大家感觉摸不着头脑的handler.
下面呢 主要从以下几个方面来讲.
1. 为什么禁止在非UI线程更新UI
2. Handler概述
3. Handler的几种使用方式
4. Handler的原理,以及handler与message queue, looper之间的关系
5. HandlerThread是什么?
6. 异步更新UI 的几种方式
7. 非UI线程真的不能更新UI吗?
为什么禁止在非UI线程更新UI?
Handler翻译成中文就是”处理者”的意思,实际上也确实如此.当我们在处理Android中多线程问题的时候,有需要处理的事情就可以去找Handler了.那么为什么会产生多线程问题呢?
Google在设计的framework的时候禁止开发者在非UI线程去更新界面UI.那么Google为什么要这么做呢?查看源码之后可以发现更新UI 的相关方法为了保证效率都是没有加上同步锁的.而更新UI绘制图形会调用底层硬件相关方法,如果不加以限制可能会产生意想不到的后果.所以为了兼顾效率与安全,就设计成只能在主线程更新UI.另外不只是Google,iOS系统也是禁止在主线程更新UI的,足以证明这样的设计是一种通用做法.
Handler概述
但是如果只是简简单单设计成只能在主线程更新UI的话,那么对开发者的素质要求势必会提高,java中的多线程问题想必大家学习的时候也是一大难点吧.开发者为了保证线程间通信的代码不会乱掉势必要自己设计一套线程间通信的框架.这样的要求未免太高,不利于Android平台的初期拓展.于是Google就在framework中封装好了这么一套线程间通信的框架.这套框架在Google的代码中也是应用相当广泛,我们常用的Activity的生命周期回调,事件传递等framework层中的代码中,Handler机制也是随处可见.下面就让我们来学习一下Handler的基本使用吧.
Handler的基本使用
Handler的使用主要和下面几个方法相关:
sendMessage()
sendMessageDelayed()
post()
postDelayed()
带delayed后缀的方法都是在原方法上延迟几秒的方法.下面只演示sendMessage()方法和post()方法.
废话不多说上代码:首先是sendMessage()方法
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
textView.setText("文字被改变啦");
}
};
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.test);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
handler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
运行结果:
这段代码里我们使用handler在子线程向主线程里发送了一条空消息.这样handlemessage方法就可以在主线程执行了
Message也可以指定并传递数据,message共有几个主要的属性.what,object,arg1,arg2.
使用示例:
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
String string = "";
for (String temp : (ArrayList<String>)msg.obj)
string += temp;
textView.setText("what:" + msg.what + "arg1" + msg.arg1 + "arg2" + msg.arg2 + "objString:"+string);
}
};
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.test);
new Thread(new Runnable() {
@Override
public void run() {
try {