Handler
Handler类可以看做工具类,用来向消息队列中插入消息的。实例化时自动绑定调用的线程Looper,当处理消息时在该线程中执行。利用这个特性,副线程发送消息,接受消息后在主线程处理,达到主线程和副线程的通讯。
在Android里可以这么理解,因为在android里你可以把UI界面当做主线程,你不能因为下载东西就一直显示下载,用户体验不好,也不被google容许,所以你点击下载就是开启子线程去下载了,手机页面该看什么你就看什么,等下载好子线程就发个message给handler它来更新UI,在你的手机界面显示或弹出一个下载好了的消息,如果不用handler下载好了你也不知道,还得自己去看。Handler和Thread:子线程是不能更新UI的,所以用Thread开启子线程后,如果需要更新UI,就通过Handler来更新UI.
而AsyncTask 中:
doInBackground(Params…) 属于子线程,后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以 调用publicProgress(Progress…)来更新任务的进度。
onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
looper类是用来封装消息循环和消息队列的一个类。
(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。
(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报如下的错误:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
把下面例子中的mHandler声明成类成员,在主线程通过mHandler发送消息即可。
总结,一般都是绑定主线程的handler,达到通讯目的,在副线程中发送消息。若要创建副线程中绑定handler,则必须先创建副线程的looper,已达到循环发送消息的目的。有两种方式达到这个目的:
1、通过handler+Looper两个类。
2、通过HandlerThread这个类,这个是android提供的利用Looper和Handler继承Thread完成。