目录:
Android的消息机制(异步处理)组成
- Message
- Handler
- 消息队列MessageQueue
- Looper
AsyncTask
Looper与Handler的关系(关键)
AsyncTask和Handler对比
RxAndroid
Android异步处理组成
- Message
- Handler
- MessageQueue
- Looper
Message
在线程之间传递的消息,可以在内部携带少量的信息,用于在不同线程之间交换数据。比如,在Activity中
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这里处理发过来的信息
if (msg.what == 1){
//收到对应的信息开始程序控制逻辑
Log.d(TAG,"收到风,开始bb");
}
}
};
然后发送信息
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
下面是Message能携带的信息类型
Handler
处理者,只要用于发送和处理信息。
发送消息一般用Handler的sendMessage方法,有时候会用带有AtTime的mHandler.sendMessageAtTime()等方法定时发送实现定时启动某些功能或更新ui的的功能。最终消息传到Handler的handleMessage方法处理
消息队列MessageQueue
主要用于存放所有通过Handler发送的的消息。这部分消息一直存放于消息队列中,等待被处理。重要的是,每个线程
只会有一个MessageQueue对象。
Looper
它是每个线程中MessageQueue的管家,这个是很重要的,当调用Looper的loop()方法后,就会进入到一个无限循环中,然后 每当发现消息队列中存在一条消息就取出,并传递到Handler的handleMessage()方法中。每个线程只会有一个Looper对象
流程
- 首先,在主线程中创建一个Handler对象,重写handleMessage方法。
- 当主线程需要进行UI操作(比如播放器更新SeekBar),就创建一个Message对象,通过Handler把消息发送出去。之后这条消息将会被添加到消息队列等待被处理,并且Looper会一直尝试从消息队列中取出待处理消息,最后发到Handler的handleMessage()方法中。
异步消息处理机制流程图Handler是在主线程中创建的,所以handleMessage()方法中的代码也会在主线程中运行。这样就不用担心子线程UI操作出错
Android也封装了上面这个流程
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
AsyncTask
Android为了方便我们在子线程中对UI进行操作,提供的工具。原理也是基于上面的异步消息处理机制流程。嗯,其实就是封装的意思。
基本用法
class AsyncTaskDemo extends AsyncTask<Params, Progress, Result>{
//四个重载方法
}
上面的AsyncTask类总共有三个范型
- Params 执行AsyncTask时传入的参数,一般用于在后台任务中使用
- Progress 后台任务如果需要进度,使用这里指定的范型作为进度的单位。
- Result 任务处理完成后,如果需要返回结果,使用这里的范型作为返回值类型
AsyncTask的重载方法
-
onPreExecute()
在后台任务执行前开始调用,用于界面上的初始化等,比如显示进度条对话框 -
doInBackground(Params...)
这里的代码会之执行在子线程,可以在这里处理所有的耗时任务,任务完成可以通过return语句来返回任务的执行结果,特殊情况下,AsyncTask的第一个范型为Void,则不返回任务的执行结果。
警告:这里不能进行UI操作,如果需要反馈当前任务的执行进度,调用publishProgress(Progress...)来完成 -
onProgressUpdate(Progress...)
在这里对UI进行操作
当在doInBackground(Params...)执行了publishProgress(Progress...)方法后,这个方法就会被调用,看参数是一样的,就是
publishProgress(Progress...)传过来的 -
onPostExecute(Result)
后台任务执行结束时被调用,Result是doInBackground(Params...)返回的数据,我们可以在这里进行最后的UI工作,比如,关闭进度条窗口
全部的就像这样
/**
* @param Void 后台任务返回空值 doInBackground()
* @param Integer 有进度条,用这个作为进度显示单位 onProgressUpdate()
* @param Boolean 用布尔型数据反馈执行结果 onPostExecute
* */
class AsyncTaskDemo extends AsyncTask<Void, Integer, Boolean>{
@Override
protected Boolean doInBackground(Void... params) {
// 后台处理耗时任务,比如下载,这里有进度
publishProgress(Progress...);//这个方法把进度发到onProgressUpdate()处理了
return null;
}
@Override
protected void onPreExecute() {
// 显示进度对话框,任务开始前
}
@Override
protected void onPostExecute(Boolean aBoolean) {
//任务完成时调用,可以响应任务结束的逻辑(用Result操作)
//关闭进度条框
}
@Override
protected void onProgressUpdate(Integer... values) {
//更新UI,比如进度条值
}
}
最后
new AsyncTaskDemo().execute();
就启动任务了
Looper与Handler的关系
Handler
A Handler allows you to send and process Message
and Runnable objects associated with a thread's MessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Looper
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare()
in the thread that is to run the loop, and then loop()
to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler
class.
Handler就是从消息队列中拿出消息,Looper是负责遍历和拿取消息队列内的消息的
Looper源码
public class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
// 。。。其他属性
// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
}
可以看到Looper的构造函数Looper()被声明为private,也就是说,在外部,我们不能直接的使用Looper的构造函数。所以,它这么创建Looper对象,看下面
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常 ,只能有一个
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper对象
sThreadLocal.set(new Looper());
}
这个方法系统会在ThreadLocal内添加一个Looper对象,并且只能有一个Looper对象,接着
public static final void loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
// 这两行没看懂= = 不过不影响理解
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志。。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
// 下面没看懂,同样不影响理解
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 回收message资源
msg.recycle();
}
}
}
当我们调用Looper.loop()这个方法后,Looper才真正的开始工作
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
获取到当前Looper的MessageQueue,每一个Looper都有一个消息队列,并且这个消息队列作为Looper的一个成员属性。
然后再while内循环这个消息队列,不断的取出数据
Message msg = queue.next(); // 取出message
判断该消息队列是否到结尾
if (msg != null)
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
最后注意下
looper()里有一句很关键
msg.target.dispatchMessage(msg)
其实是调用了
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//这里
handleMessage(msg);
}
}
恩。关键在handleMessage(msg);很熟悉吧
AsyncTask和Handler对比
AsyncTask
- 优点:简单,快捷,过程可控
- 缺点:使用多个异步操作并进行UI变更时,将会变复杂
Handler
- 优点:结构清晰,功能定义明确,适合多个后台任务,
- 缺点:单个后台异步处理,代码过多(相对AsyncTask)
RxAndroid
....恕我直言,不是针对上面某一个人........
RxAndroid:上面的Handler。AsyncTask都是辣鸡
优点:可以更好的处理内存泄露问题, 代码也更加优雅和可读, 选择执行线程和监听线程也更加方便。
建设中。插眼
Handler与AsyncTask参考自郭霖《第一行代码》
晚安
网友评论