正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)
Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子。
package com.example.loopertest; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log; public class MainActivity extends Activity { public static final int SIGNAL_1 = 0x1;
public static final int SIGNAL_2 = 0x2; public static int flagValue = 0;
private LooperThread thread;
private Handler uiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case SIGNAL_1:
Log.v("MainActivity", "主线程收到子线程发来的消息");
flagValue++;
if (flagValue == 5) {
Log.v("MainActivity", "now flagvalue is over 5");
Log.v("MainActivity",
"quit 前 thread.isAlive?" + thread.isAlive());
thread.cHandler.getLooper().quit();
Log.v("MainActivity",
"quit 后 thread.isAlive?" + thread.isAlive());
} else {
Log.v("MainActivity", "thread.isAlive?" + thread.isAlive());
thread.cHandler.sendEmptyMessageDelayed(SIGNAL_1, 3000);
}
break;
case SIGNAL_2:
thread.cHandler.sendEmptyMessage(SIGNAL_1);
break;
default:
break;
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); thread = new LooperThread();
thread.start();
uiHandler.sendEmptyMessage(SIGNAL_2); new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.v("MainActivity",
"第三个子线程里面每隔10s判断 thread.isAlive?"
+ thread.isAlive());
}
}
}.start(); } class LooperThread extends Thread {
public Handler cHandler; @Override
public void run() { // 实例化messagequeue
Looper.prepare(); cHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case SIGNAL_1:
Log.v("MainActivity", "子线程收到主线程发来的消息");
uiHandler.sendEmptyMessageDelayed(SIGNAL_1, 3000);
break;
default:
break;
}
}
};
Log.v("MainActivity", "loop以前的语句");
Looper.loop(); Log.v("MainActivity", "loop以后的语句"); } } }
看一下执行结果
04-30 07:17:58.754: V/MainActivity(597): loop以前的语句
04-30 07:17:58.784: V/MainActivity(597): 子线程收到主线程发来的消息
04-30 07:18:01.794: V/MainActivity(597): 主线程收到子线程发来的消息
04-30 07:18:01.794: V/MainActivity(597): thread.isAlive?true
04-30 07:18:04.804: V/MainActivity(597): 子线程收到主线程发来的消息
04-30 07:18:07.814: V/MainActivity(597): 主线程收到子线程发来的消息
04-30 07:18:07.814: V/MainActivity(597): thread.isAlive?true
04-30 07:18:08.780: V/MainActivity(597): 第三个子线程里面每隔10s判断 thread.isAlive?true
04-30 07:18:10.824: V/MainActivity(597): 子线程收到主线程发来的消息
04-30 07:18:13.834: V/MainActivity(597): 主线程收到子线程发来的消息
04-30 07:18:13.834: V/MainActivity(597): thread.isAlive?true
04-30 07:18:16.844: V/MainActivity(597): 子线程收到主线程发来的消息
04-30 07:18:18.782: V/MainActivity(597): 第三个子线程里面每隔10s判断 thread.isAlive?true
04-30 07:18:19.844: V/MainActivity(597): 主线程收到子线程发来的消息
04-30 07:18:19.844: V/MainActivity(597): thread.isAlive?true
04-30 07:18:22.854: V/MainActivity(597): 子线程收到主线程发来的消息
04-30 07:18:25.864: V/MainActivity(597): 主线程收到子线程发来的消息
04-30 07:18:25.864: V/MainActivity(597): now flagvalue is over 5
04-30 07:18:25.864: V/MainActivity(597): quit 前 thread.isAlive?true
04-30 07:18:25.874: V/MainActivity(597): loop以后的语句
04-30 07:18:25.874: V/MainActivity(597): quit 后 thread.isAlive?false
04-30 07:18:28.785: V/MainActivity(597): 第三个子线程里面每隔10s判断 thread.isAlive?false
这个例子就是用来 在android里面 主线程和子线程进行通信的,大家可以看一下代码,另外还有第三个线程在不断侦测 子线程如何结束。
实际上就是子线程和主线程每隔3s 通信一次,然后通信的时候那个参数值 就每次加1,一直加到5的时候 子线程就结束了。
例子里面也可以看出来 looper的消息队列在没有quit的时候 子线程是会一直执行的,也就是谁looper.loop()后面的代码是不会执行的,
只有当quit以后 loop()的代码才会执行,这点大家要注意了。
然后我们可以借着这个清晰得例子,来理一下 looper和handler之间是如何通信的。
首先我们调用的是Looper.prepare(); 这句话,我们来看一下源码是怎么写的,
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
一下就能看出来 如果get()的值不是空 那么就要抛出这个异常,这样就能解释我们一个线程 肯定只能有一个looper了,并且Looper.prepare() 在一个线程里面只能调用一次,否则也要抛异常。
当然了 我们可以点到这个set方法里面看一下 大概做了什么操作。
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
然后我们进入threadlocal这个类里面的set方法看看。
/**
* Sets the value of this variable for the current thread. If set to
* {@code null}, the value will be set to null and the underlying entry will
* still be present.
*
* @param value the new value of the variable for the caller thread.
*/
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
到这个地方就很明显了 看第9行,
Thread currentThread = Thread.currentThread();
这也就是为什么说一个线程只能有一个looper。也能说明Looper和线程的绑定 就是在这个方法里面完成的。有兴趣的同学还可以继续看values这个内部类,我们在这里先不去挖的太深。
说完prepare 方法 我们再说说loop方法,因为有很多人都不明白 为什么loop方法以后的语句 都不执行。我们还是直接上源代码。
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity(); while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
} long wallStart = 0;
long threadStart = 0; // This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
} msg.target.dispatchMessage(msg); if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
} // Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "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);
} msg.recycle();
}
}
}
6-10行 我们能看出来 是取得了 looper的 消息队列,然后17行开始 就是一个while true循环了!这也就能解释为啥loop方法一调用我们loop后面的代码就不会执行,
18行也能看出来,代码告诉我们是不断的在消息队列里面取消息,并且有可能会阻塞~
我们再来看一下这个37行的代码
msg.target.dispatchMessage(msg);
到这个地方 可能很多人就能猜到了,这个地方就是我们处理消息的地方。那么这个msg.target我们应该怎么理解?(很多人无法理解looper handler 之间的关系 其实是因为这个地方始终理解不了)
我们可以先放一放,先去看我们handler的代码,在我们文中开头的第一个例子中,我们在prepare()以后 就创建了一个handler,
我们去看看handler的构造函数。
/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
} mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
17-21行 可以看出来,我们在调用handler的构造函数的时候,会先取当前线程的looper 如果取不到就会报异常了~~
然后我们发消息的时候是调用的send函数,
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
经过一番调查,我们发现最终都是调用的这个方法
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
注意看 24行,
msg.target = this;
然后我们回到loop方法里面
msg.target.dispatchMessage(msg);
一下就能看出来,其实target就是handler。
所以loop方法里面处理消息实际上就是调用的handler的dispatchMessage 这个方法!
我们进去看这个方法
/**
* 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);
}
}
看14行,发现其实调用的是handler的这个方法
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
而这个方法 也是我们每次都去重写的。到这里 我们就算是理清楚了 handler 和looper 之间消息传递的一个过程。
其实就是 先调用looper.prepare() 然后才能创建handler. 一个线程只能有一个looper 一个线程队列 messagequeue.
handler发消息的时候 发message的时候 实际上是把自己(handler本身)放在了message的 target变量里面,这样在loop
方法里面无线循环的时候 我们才能回调到 handler的handleMessage方法~~~~
同样的我们也可以分析一下 为什么quit方法 可以让loop循环结束?(我就不分析了 留给大家自己分析 其实也是不难的)
搞清楚looper和handler的关系以后 我们就可以看看 AsyncTask这个东西。
package com.example.asynctest; import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView; public class MainActivity extends Activity { private TextView tv1; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = (TextView) this.findViewById(R.id.tv1);
/**
* Task的实例必须在UI thread中创建; execute方法必须在UI thread中调用;
* 不要手动的调用onPreExecute(),
* onPostExecute(Result),doInBackground(Params...),
* onProgressUpdate(Progress...)这几个方法; 该task只能被执行一次,否则多次调用时将会出现异常;
*/
new MyAsyncTask().execute(); } private class MyAsyncTask extends AsyncTask<Void, Integer, Void> { @Override
protected void onPreExecute() {
// TODO Auto-generated method stub
Log.v("mainactivity", Thread.currentThread().getName()
+ " onPreExecute ");
} /**
* 这里不能直接操作ui 因为不是在主线程里操作的
*/
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
// 模拟数据的加载,耗时的任务
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
} Log.v("mainactivity", Thread.currentThread().getName()
+ " doInBackground ");
return null;
} /**
* 在主线程执行
*/
@Override
protected void onProgressUpdate(Integer... values) {
tv1.setText(values[0] + "");
Log.v("mainactivity", Thread.currentThread().getName()
+ " onProgressUpdate ");
} /**
* 可以操作ui
*/
@Override
protected void onPostExecute(Void result) {
// 进行数据加载完成后的UI操作
tv1.setText("LOAD DATA SUCCESS ");
Log.e("mainactivity", Thread.currentThread().getName()
+ " onPostExecute ");
}
} }
我们看一下 日志和运行效果。
看一下日志
04-30 09:04:16.345: V/mainactivity(935): main onPreExecute
04-30 09:04:16.494: V/mainactivity(935): main onProgressUpdate
04-30 09:04:16.884: V/mainactivity(935): main onProgressUpdate
04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.264: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.264: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.284: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.284: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.365: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.414: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.414: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.484: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.534: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.614: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.684: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.754: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.834: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:17.994: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.074: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.154: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.244: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.324: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.404: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.484: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.565: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.644: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.724: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.804: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.884: V/mainactivity(935): main onProgressUpdate
04-30 09:04:18.964: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.053: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.134: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.214: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.294: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.375: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.454: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.534: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.614: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.694: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.784: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.864: V/mainactivity(935): main onProgressUpdate
04-30 09:04:19.944: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.024: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.104: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.184: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.264: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.344: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.425: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.504: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.593: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.674: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.754: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.834: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:20.994: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.073: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.154: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.233: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.313: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.404: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.485: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.563: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.643: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.723: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.803: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.883: V/mainactivity(935): main onProgressUpdate
04-30 09:04:21.963: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.043: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.123: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.204: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.293: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.373: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.454: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.533: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.613: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.693: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.773: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.854: V/mainactivity(935): main onProgressUpdate
04-30 09:04:22.934: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.024: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.103: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.184: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.264: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.344: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.424: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.504: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.584: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.664: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.744: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.834: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.914: V/mainactivity(935): main onProgressUpdate
04-30 09:04:23.994: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.074: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.154: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.234: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.314: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.394: V/mainactivity(935): main onProgressUpdate
04-30 09:04:24.474: V/mainactivity(935): AsyncTask #5 doInBackground
04-30 09:04:24.474: V/mainactivity(935): main onProgressUpdate
其实还是蛮好理解的,可以清楚的看到
AsyncTask 的执行周期 以及那些方法都是在哪个线程执行的(ui还是子?) 然后 我们就来分析一下 这个AsyncTask类到底是怎么做的? 这是我们调用的excute方法,
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
跟进去 看看。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
} mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params;
exec.execute(mFuture); return this;
}
3-13行 我们可以看出来,这个excute方法 只能执行一次,不然就要抛异常。同时 也能看出来
onPreExecute(); 这个方法是在主线程执行的。 然后我们着重看一下19行,这个地方,mWorker 是什么? 找了一下 发现
private final WorkerRunnable<Params, Result> mWorker;
实际上 是Workerrunnable这个类的对象,我们进去看看这个类。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
发现这是一个静态的抽象类~并且继承了
Callable 这个接口 当然了 因为这是抽象类,所以我们无需实现这个接口。 既然
mWorker 是 WorkerRunnable 他的对象,哪我们去看看 是如何new出来的呢?看构造方法
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
}; mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get(); postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}
到这 我们相信 mWorker大家已经知道是怎么回事了 5-12行表明了mWorker 是一个对象,并且他的回调方法里面 也调用了
doInBackground 这个方法,至与
postResult 这个方法 我们可以等会再看,先往下面继续看,我们再拿到
mWorker 这个对象以后 又利用他 去初始化了
mFuture 这个对象,且这个对象是由
FutureTask 这个类生成的,哪我们就去看看这个类。
public class FutureTask<V> implements RunnableFuture<V> {
发现 这类 继承自 RunnableFuture 这个接口,哪我们去看看这个接口,
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
我们发现原来 看似复杂的FutureTask 也不过就是一个Runnable 对象吗~~
回到excute方法
我们发现了 这句话
exec.execute(mFuture);
实际上 就是这么调用的
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
那么我们赶紧去看一下 sDefaultExecutor 这是什么东西?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
再看看
SERIAL_EXECUTOR 这是什么?
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
原来是一个静态的 final 对象~~且这个对象是由SerialExecutor 这个类生成的,哪我们赶紧去看一下这个类,
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive; public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
} protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
第二行 明显的 是创建了一个线程队列
当执行excute方法的时候
实际上就是把这个runnable 先放到线程队列里面,然后再去执行线程队列里的第一个线程,
20-24行 就是从这个线程队列里面取值,如果能取到 就执行这句话
THREAD_POOL_EXECUTOR.execute(mActive);
而THREAD_POOL_EXECUTOR就是一个线程池。
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
也可以看一下这个常量
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
有兴趣的可以看下这个线程池的参数设置。
但实际上我们回到
SerialExecutor 这个类的5=15行 我们发现 实际上我们还是从队列里面取任务出来做,任务做完了,才去取下一个任务。 所以 AsyncTask 他本质上还是一个单线程执行的 东西,(当然执行的时候是在子线程 而不是主线程执行的) 我们再回到一开始的地方
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
} mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params;
exec.execute(mFuture); return this;
}
实际上我们执行的 就是mFuture 这个任务,这个任务在子线程里面被执行。
所以我们去看一下FutureTask 他的run方法
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
public void run() {
sync.innerRun();
}
找到run方法
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return; runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
可以看出来 run方法实际执行的是
callable.call 这个方法,所谓这个方法 不过也是我们一开始构造函数里的mWorker对象罢了,
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
}; mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get(); postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}
所以线程中执行的是3-8行里的代码!!!!!!!!!!!!!!!!!!!!!!!!!! 所以doInBackground 这方法是在子线程里面去执行的。 执行完毕以后才调用了下面的方法
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
最终我们找到这个handler里面看一下 看看这里面做了什么。
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
再看看这个finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
于是 整个AsyncTask的生命周期 就全部得到印证,执行顺序 到这里也就差不多了。 至此 我们 AsyncTask,Looper,Handler 这三者的源码分析 也就告一段落。
---恢复内容结束---
正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)的更多相关文章
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- silverlight Canvas、StackPanel、Grid三者之间的关系
学习 silverlight 首先Canvas.StackPanel.Grid 博客园里看到jailu的这篇文章整理得很好 贴下来: Silverlight提供了非常灵活的布局管理系统,让程序员和 ...
- 转:spring data jpa、 hibernate、 jpa 三者之间的关系
原文链接:spring data jpa. hibernate. jpa 三者之间的关系 spring data jpa hibernate jpa 三者之间的关系 JPA规范与ORM框架之间的关系是 ...
- Window系统、主函数和窗体函数这三者之间的关系
理解Window系统.主窗体.窗体函数这三者之间的关系,对于编写Windows程序十分重要. 主函数和窗体函数都是由Windows系统来调用的函数.仅仅只是主函数是程序启动之后.系统首先调用的函数: ...
- 【面向对象】----【prototype&&__proto__&&实例化对象三者之间的关系】(四)-----【巷子】
1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...
- 【面向对象】【prototype&&__proto__&&实例化对象三者之间的关系】
1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...
- 面向对象---prototype、__proto__、实例化对象三者之间的关系
1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...
- tep环境变量、fixtures、用例三者之间的关系
tep是一款测试工具,在pytest测试框架基础上集成了第三方包,提供项目脚手架,帮助以写Python代码方式,快速实现自动化项目落地. 在tep项目中,自动化测试用例都是放到tests目录下的,每个 ...
- js中数据、内存、变量的概念及三者之间的关系
目录 数据.内存.变量的概念及三者之间的关系 什么是数据 数据的特点 什么是内存 栈内存 堆内存 JS引擎如何管理内存 什么是变量 变量是普通类型时 变量是引用类型时 数据.内存.变量的三者之间的关系 ...
随机推荐
- JavaScript事件冒泡和事件委托
JavaScript事件冒泡和事件委托 付建宇 - 2 条评论 接触JavaScript不久,学的东西也不是特别多.小雨就是习惯把平时学到的东西拿出来分享.一方面加强自己的印象,一方面可以让自己的经验 ...
- 关于java中split的使用
之前在http://shukuiyan.iteye.com/blog/507915文中已经叙述过这个问题,但是最近一次笔试中居然有碰到了这个知识点,而且还做错了,囧!学艺不精啊.题目大概是这样的: ) ...
- Android笔记——导入Github开源项目CircleRefreshLayout
百度n久都找不到android studio导入第三方类库的正确方法,纠结睡不着 ,最后终于蒙到了方法,原来想太多了 ---------------------------------------- ...
- HTML5文档结构语义:页眉的header和hgroup标签使用
HTML5提供了新的结构元素——例如header.hgroup.article.section.footer.nav等来定义网页,将使网页结构更加简洁严谨,语义更加结构化,而不用迂回通过class或i ...
- Item2 + zsh
转自 http://11ten.gitcafe.io/book-a/iTerm2/index.html iTerm2的主要特点: 开源免费. 兼容性比默认Terminal更好.对于经常要远程使用的情况 ...
- 在VS2010中使用Git(转)
在之前的一片博客<Windows 下使用Git管理Github项目>中简单介绍了在Windows环境中使用Git管理Github项目,但是是使用命令行来进行操作的,本文将简单介绍下在VS2 ...
- AppDomain 应用程序域
应用程序域 一.什么是应用程序域? 应用程序域 (application domain) (AppDomain) 一种边界,它由公共语言运行库围绕同一应用程序范围内创建的对象建立(即,从应用程序入口点 ...
- 怎样用delphi关闭并重新启动 explorer.exe进程
uses Tlhelp32; function KillTask(ExeFileName:string):integer; const PROCESS_TERMINATE = $0001; var C ...
- CF 2013-2014CTS01E04(Killer Challenge-将质因数存在 进行Bitmask)
首先,把P进行质因数分解,每一个不用的质因数压成1位 f[i][j]表示1前i位用j“拥有”的质因数表示. 然后都懂得... #include<cstdio> #include<cs ...
- Android开发环境的安装 Eclipse
Android开发环境的安装 1 IDE Android可以使用开发的IDE有Eclipse 或者 Android Studio.Android Studio还处于v 0.1.x版本,是early a ...