Handler详解

来源:互联网 发布:淘宝店花呗怎么开通 编辑:程序博客网 时间:2024/06/02 01:06

Handler10问10答:

1.什么是Handler?

Handler是Android消息机制上层接口
2.Handler的作用?
将一个任务切换到某个指定的线程中去执行
3.Android为什么要提供Handler?
因为Android规定访问UI只能在主线程中进行,但是又不能在主线程中进行耗时操作,
否则会导致ANR,因此系统提供了Handler来解决该问题
4.系统为什么不允许在子线程中访问UI呢?
答:因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能导致UI控件处于不可预期的状态
5.Handler机制是靠什么支撑的?
答:MessageQueue 和 Looper
6.什么是MessageQueue,它的作用是什么?
答:顾名思义,MessageQueue是消息队列,
它的作用只有两个:
a.通过调用equeueMessage()方法,往消息队列中插入一条消息;
插入消息的操作是通过单列表的方式;
b.通过调用next()方法,从消息队列中取出一条消息,并从消息队列中移除;
它是一个死循环的方法,如果没有消息,next()方法会一直阻塞在这里;
7.什么是Looper,它的作用是什么?
答:可以看到,MessageQueue只是用来插入和取出消息的,并不能处理消息,这个时候
Looper就出现了来弥补这个功能;
Looper通过调用prepare()方法来创建当前线程的Looper对象
并通过调用loop()方法开启处理消息死循环模式
在loop()方法中MessageQueue调用next()方法来取出一个又一个的消息,
并调用了Handler.dispatchMessage()方法来处理消息
8.Handler是怎么把任务切换到指定线程中的呢?
答:由于Handler.dispatchMessage()方法是在创建Handler时所使用的Looper中执行的,自然而然将代码逻辑切换到指定的线程中去了
9.Handler的工作原理是什么?
答:Handler主要包含消息的发送和接收
发送消息通过:post或者sendMessage方法
10.使用Handler必须为线程创建Looper,为什么我们在主线程中却没有创建呢?
答:这是因为Android的主线程也就是ActivityThread,入口方法为main(),
在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper

以及MessageQueue,并通过Looper.loop()开启主线程的循环

☆☆☆

相信很多人都会用Handler,但你写的真的没有问题吗?

你有考虑过使用Handler可能造成的内存溢出的问题吗?

下面写一个标准代码解决Handler可能造成的溢出问题:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //使用handler延时2分钟执行一个任务(为了测试)        mHandler.postDelayed(new Runnable() {            @Override            public void run() {            }        }, 1000 * 60 * 2);        //之后关闭activity        finish();    }    private MyHanlder mHandler = new MyHanlder(this);    /**     * 不能让Handler持有Activity的强引用     * 不然,就算Activity调用了finish方法     * 垃圾回收器依然不会回收它,这样,就可能     * 造成内存泄漏,最终可能导致内存溢出。     */    private static class MyHanlder extends Handler {        WeakReference<MainActivity> weakReference;        public MyHanlder(MainActivity mainActivity) {            //Activity的引用变为弱引用            weakReference = new WeakReference<MainActivity>(mainActivity);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            //获取Activity的强引用            MainActivity mainActivity = weakReference.get();            //如果Activity没有被垃圾回收器回收            if (mainActivity != null) {                //这个时候在做一些操作即可            }        }    }}
详解

当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可能通过Handler来操作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了HandlerpostDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。


原创粉丝点击