1、IntentService
IntentService是继承并处理异步请求的一个类,在IntentService中有一个工作线程来处理耗时操作,启动方法和常规Service一样,不同的是它不需要我们手动控制或销毁,而且IntentService可以启动多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent
回调方法中执行,并且是串行执行,必须等待前一个执行完成后才会执行下一个。
看源码IntentService
实际上就是内部实现了一个Handler
,我们知道每启动一次service,如果这个service已经存在就会调用onStartCommand,否则就先执行onCreate方法,在onStartCommand
方法中默认会调用onStart方法,IntentService的onStart
方法源码如下:1
2
3
4
5
6public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看到在这个方法中会向自己的handler提交一条消息,然后我们看它的handler源码的handleMessage方法:1
2
3
4public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
我们可以看到会调用onHandleIntent
,然后执行完之后自动调用stopself
。这就是我们使用IntentService
默认必须实现它的onHandleIntent
方法,而且它执行完成后会自动销毁的原因了。
2、Activity中的runOnUiThread(Runnable runnable)
runOnUiThread是Activity中独有的方法,可以实现与UI主线程的通信,那它是怎么通信的呢?
首先看这个方法的源码:1
2
3
4
5
6
7public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
这段代码什么意思呢?就是当前的线程如果不是UI线程,就向handler提交一个任务,否则就直接调用run方法。所以这个方法就是在activity开启耗时线程执行完成后去提交UI修改。
3、View.post或postDelayed
这个方法也是和runOnUiThread类似的,可以实现与UI主线程的通信,不同的是它提交到的是HandlerActionQueue
去解决,而且它可以延时执行。
4、AsyncTask
AsyncTask顾名思义就是Android的异步任务,同样在异步任务中也可以执行耗时操作并更新UI,用过异步任务的都知道AsyncTask是一个抽象类,使用它必须继承它并重写它的方法,必须实现它的doInBackground
方法,但是一般情况下我们都需要使用它提供的更多的功能,也就是继承AsyncTask<Params,Progress,Result>
。这里面三个参数代表什么意思呢?第一个Params
表示启动任务时你需要携带给它的参数类型,也就是调用execute方法向里面传递的参数,后面讨论它传递到哪里去了,第二个Progress
表示后台任务执行中返回进度值的类型,第三个Result
表示后台任务执行完成后返回结果的类型。
我们一般会重写以下4个方法:
- doInBackground:必须重写的方法,异步执行后台线程要完成的任务,耗时操作将在此方法中完成
- onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
- onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
- onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.
这4个方法的调用顺序是怎样的呢?我们从调用execute方法开始看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
...
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
private final FutureTask<Result> mFuture;
我们可以看到首先是onPreExecute()
最先调用的,所以我们在执行耗时操作前先使用它初始化,然后我们看到它将execute传递进来的params数组赋给了一个数组,mWorker在构造函数中初始化,然后执行exec.execute(mFuture)
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//一个双端队列,存着工作任务
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);
}
}
我们看这个execute方法,它的参数是FutureTask
类型的Runnable,传入的mFuture会在一个新的工作任务中执行,然后调用scheduleNext()
执行下一个任务。所以现在就到了FutureTask.run
方法了,mFuture
是在谁初始化的呢?mFuture.run方法会调用什么呢?我们从构造函数中可以看到:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41//异步任务的构造方法,默认调用
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//WorkerRunnable的初始化
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
//FutureTask任务的初始化
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
mFuture是mWorker这个参数去初始化的,关于FutureTask的知识可以去看Java并发编程:Callable、Future和FutureTask。
所以最终调用的是mWorker
的call
方法,在call
方法里面我们看到它调用了doInBackground(mParams)
,而且传入了mParams
数组,doInBackground
方法的返回值就是Result
类型,最后调用postResult(Result result)
方法,1
2
3
4
5
6
7private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可以看到这个方法是向它的handler提交了一条消息。
我们来看这个handler的消息处理方法:1
2
3
4
5
6
7
8
9
10
11
12
13@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;
}
}
可以看到它只会处理两种消息,一种是异步任务执行完成,一种是在异步方法执行中调用,那我们接着看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
可以看到执行完成后调用的finish方法,如果正常执行完成,调用的是onPostExecute(result)
,所以我们说onPostExecute
方法执行在doInBackground
方法后,我们说在doInBackground
方法中调用publishProgress
方法,会调用onProgressUpdate
方法,也可以从上面的源码中得出结论。
5、HandlerThread
一个Android封装的轻量级异步类。知道它的工作原理也就知道了它的优点,它是利用Thread+Handler
实现的,它继承自Thread,使用它需要先创建一个HandlerThread实例,紧接着调用start将这个线程启动起来,它的run方法为:1
2
3
4
5
6
7
8
9
10
11
12public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
6、Handler
从上面所有的方式中我们都可以看到Handler的身影,所以说学习Android必须先学好Handler。
关于Handler的博客就太多了,可以看Android Handler:手把手带你深入分析 Handler机制源码,Android:这是一份Handler消息传递机制 的使用教程,Android Handler:图文解析 Handler通信机制 的工作原理,上面三篇从使用,到原理,到源码由浅入深仔细讲解了Handler机制。
问
:在线程中使用Handler时(除了Android主线程)必须把它放在Looper.prepare()
和Looper.loop()
之间。否则会抛出RuntimeException异常。但是为什么要这么做呢?答
:通俗的讲Handler机制就是主线程中有一个无限循环,与UI主线程绑定起来,它会一直循环,拿到一个消息之后就会去主线程中去调用handleMessage方法。
其实就是Looper类和Handler类,Looper类封装了消息循环和消息队列,当你调用了Looper.prepare()之后,这个Looper就开始启用了,一般情况主线程在Application初始化的时候就已经自动创建一个Looper,因为一个线程就只能有一个Looper,所以在非主线程中先要调用Looper.prepare()先创建一个Looper。调用Looper.loop()之后就开始了从MessageQueue中取出消息的无限循环。