5. 消息机制和多线程的使用
UI线程的消息循环是在ActivityThread方法中创建的, 该函数为Android应用程序的入口.
在Android应用启动的时候, 会默认有一个主线程(UI线程), 这个线程会关联一个消息队列, 所有操作都会被封装成消息交给主线程来处理.
Looper总结:
- 通过Looper.prepare来创建looper对象(消息队列封装在Looper对象中), 并且保存在sThreadLocal中.
- 消息循环的建立通过Looper.loop()方法, loop方法实际上是建立一个死循环, 不断从消息队列中取出消息.
Handler将消息发送给消息队列, 消息队列又将消息分发给Handler来处理.
Message的两个重要成员变量
Hander target;
Runnable callback;
不管是post一个Runnable(包装成Message, callback设置为runnable成员变量)还是sendMessage, 都会调用sendMessageDelayed(msg, time)方法, Handler最终将消息追加到MessageQueue中, 而Looper不断取出从MessageQueue中读取消息, 并调用Handler的dispathMessage来处理消息.
dispathMessage方法是一个分发方法, 如果Runnable类型的callback变量不为空, 则callback.run中执行更新UI的代码, 否则会走到handMessage这个分支.
Handler构造方法中通过Looper.myLooper来获取Looper对象.
//1. 成员变量mLooper的获得
mLooper = Looper.myLooper();
//1. Looper.myLooper的源码
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
安卓中多线程的实现
使用JavaSE中线程 和 线程池,
为了方便封装了一些常用的类AsyncTask, HandlerThread.
线程池的优点
- 重用存在的线程, 减少对象创建,销毁的开销
- 有效控制最大的并发线程数, 提高系统资源的使用率, 同时避免过多资源竞争, 避免堵塞
- 提供定时执行, 单线程, 并发数控制等功能
在android平台, 由于资源有限, 最常用的就是通过Executors.newFixedThreadPool(int size)来启动固定数量的线程池.
AsyncTask的原理
onPreExecute
doInBackground
onProgressUpdate
onPostExecute
概括来说, 我调用execute方法后, execute方法先调用onPreExecute方法,
然后由ThreadPoolExecutors实例sExecutor执行一个FutureTask任务, 这个过程中doInBackground将被调用, 如果在doInBackground中调用了publicProgress方法, 则通过sHandler发送一条MESSAGE_POST_PROGRESS消息, 更新进度;
如果遇到异常, 则发送一条MESSAGE_POST_CANCEL消息, sHandler处理消息时, onCancelled方法会被调用;
如果执行成功, 则发送一条MESSAGE_POST_RESULT的消息, sHandler处理消息时会调用onPostExectute(result)方法, 让用户得以在UI线程处理结果.
总的来说, AsyncTask的本质是使用线程池技术 和 Handler封装, 较少了处理问题的复杂度, 提高了开发效率.