Android通过Looper、Handler来实现消息循环机制,android的消息循环是针对线程的,每一个线程都可以有自己的消息队列和消息循环。
Android中的Looper负责管理线程的消息队列和消息循环,我们可以通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前线程的主线程的Looper对象。
一个线程可以有一个消息队列和消息循环,但是创建的工作线程默认是没有消息队列和消息循环的,如果想让工作线程有消息队列和消息循环,就要在线程中先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()来进入循环。
Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。一个Looper对应一个MessageQueue,一个线程对应一个Looper,一个Looper可以对应多个Handler。
Handler的内部类使用导致的内存泄漏:
privateHandler handler =new Handler()
{
publicvoidhandleMessage(android.os.Message msg) {
if(msg.what == 1)
{
noteBookAdapter.notifyDataSetChanged();
}
}
};
上面是一段简单的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被持有引用而无法被回收。
为了避免内存泄漏,我们应该使用静态内部类,这样就不会持有外部Activity的引用。