1、Handler在develpoer上的描述:
大致翻译:
一个Handler允许你发送和处理和这个进程相关联的消息队列中的消息和Runnable对象。每个Handler实例都与一个单独的线程关联并且在该线程的消息队列中。当创建一个新的处理程序,它是绑定到创建它的线程的线程/消息队列,从这一点上,它将传递消息和runnable对象,消息队列和执行他们出来的消息队列。
2、Handler有两个主要用途:
(1)更新ui
(2)发送消息,处理消息。
3、Handler常用方法:
1、post类方法允许你排列一个Runnable对象到主线程队列中
post(Runnable)
postDelayed(Runnable long)
2、sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新。
sendEmptyMessage(int)
sendMessage(Message)
sendMessageDelayed(Message,long)
4、android中为什么只能通过Handler更新UI。
根本目的:解决多线程并发产生更新UI错误的情况。
如果在一个activity中有多个线程更新UI,并且没有任何管理机制,会产生更新UI界面错乱的情况。因此为了避免这样的情况:android提供了handler这样一套机制让我们更新UI,我们也就不用考虑多线程下的更新UI问题,所有的更新UI操作,都是在主线程的消息队列中去轮询处理。
5、Handler的原理:
1、Looper:内部包含一个消息队列MessageQueue,所有的Handler发送的消息都到这个消息队列中。
Looper.looper方法,是一个死循环,不断的从MessageQueue中取出消息,如果有消息就取出消息。
2、MessageQueue是一个消息队列,可以添加消息,也可以处理消息。
3、Handler负责发送消息和接收传递过来的消息,从而更新UI。
6、用handler实现计时器
public class MainActivity extends Activity {
private MyHandler handler;
private int a = 0;
private TextView tv_time;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_time = (TextView) findViewById(R.id.tv_time);
handler = new MyHandler();
new Thread() {
public void run() {
handler.postDelayed(this, 1000);
a++;
tv_time.setText(a + "");
// handler.sendEmptyMessage(1);
};
}.start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
// 处理不同的消息信息;
// switch (msg.what) {
// case 1:
// tv_time.setText("这是1传来的");
// break;
//
// case 2:
// tv_time.setText("这是2传来的");
// break;
// }
super.handleMessage(msg);
}
}
}
7、发送handler所携带的消息。
Message msg = new Message();
1、msg.what = 0; (值随意定义,和handlemessage 匹配就可以)
2、msg.agr1,2在handler中从msg中取出(arg1,arge可以携带两个参数);
3、msg.obj:可以传递一个对象。
class Person {
public String name;
public int age;
}
Message message=new Message();
Person p=new Person();
p.name="张三";
p.age=24;
message.obj=p;
handler.sendMessage(message);
8、handler引起的内存泄露问题
当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可能通过Handler来操作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
解决办法:
方法1、在activity销毁的时候结束后台线程
方法2、将Handler声明为静态类。
static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}