一.Handler的四大组件和运作机制
handler其实就是androidSDK提供给我们开发者方便进行异步消息处理的类
例如,asynctask,retrofit都是封装了handler
注意:
1.每一给线程只能有一个looper,主线程中创建looper,并且在looper内创建messagequeue
2.Looper类主要是为每个线程开启的单独的消息循环
3.messagequeue通过looper来管理message
4.messagequeue利用先进先出的原理来处理message
5.handler的作用就是发送消息和处理消息
6.handler是looper的一个接口
7.在非主线程中直接new Handler是不可以,除非先创建Looper的对象
整体流程:创建handler的时候回获取到当前线程的looper,然后通过这个looper获取到这个消息队列meessagequeue,然后通过handler来发送消息message,将message发送到消息队列messagequeue,然后再通过looper轮询消息队列取出消息再交给handler处理,这个时候再handler里面的handlermessage方法
1>在什么情况下使用handler会造成内存泄露
private Handler handler =new Handler(){
public void handleMessage(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被持有引用而无法被回收。
2>如何解决因为handler所引起的内存泄露
方法一:通过程序逻辑来进行保护。
1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方法二:将Handler声明为静态类。
在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。
静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)。
二.AsyncTask
1.Handler+线程池的封装
1>onPreExecute()----->运行在UI线程中,在调用DoInBackground()之前执行,可以做初始化操作
2>doInbackground()----->后台运行,非UI线程,可以执行耗时方法
3>onPostExecute()------>运行在UI线程中,在doinbackground()执行完毕后执行
4>onProgressUpdate()----->在publishProgress()被调用后执行,publishProgress()用于更新进度,在UI线程中执行
注意要点:
1>AsyncTask的实例必须在主线程中创建
2>AsyncTask的excute方法必须在主线程中调用
3>回调方法,android会自动调用
4>一个AsyncTack的实例,只能执行一次execute方法