在Android开发过程中,我们经常用到多线程的开发,尤其是因为在UI线程中我们不能进行耗时操作,所以很多时候需要在线程中进行操作。好在Android中有很多架构供我们使用。本文进行简单整理。主要有AsyncTask,HandlerThread,IntentService.
AsyncTask
1. 简单介绍
AsyncTask是Android提供的一个轻量级的异步任务类,它对Thread(线程池)和Handler进行了封装。Android之所以提供AsyncTask这个类,就是为了方便我们在后台线程中执行操作,然后将结果发送给主线程,从而在主线程中进行UI更新等操作。在使用AsyncTask时,我们无需关注Thread和Handler,AsyncTask内部会对其进行管理,这样我们就只需要关注于我们的业务逻辑即可。
2. 使用
2.1 AsyncTask 构造函数:
public abstract class AsyncTask<Params, Progress, Result>{}
Params表示用于AsyncTask执行任务的参数的类型
Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型
Result表示任务全部完成后所返回的数据类型
我们通过调用AsyncTask的execute()方法传入参数并执行任务,然后AsyncTask会依次调用以下四个方法:
2.2 四个核心方法,按照阶段进行介绍
onPreExecute() 方法签名 @MainThread ;
此方法会在后台任务执行前被调用,用于进行一些准备工作,主线程中执行
doInBackground(Params... params) 方法签名 @WorkerThread ;
//此方法中定义要执行的后台任务,在这个方法中可以调用publishProgress来更新任务进度(publishProgress内部会调用onProgressUpdate方法)
onProgressUpdate(Progress... values) 方法签名 @MainThread
//由publishProgress内部调用,表示任务进度更新,进行UI上的提示
onPostExecute(Result result) 方法签名 @MainThread
//后台任务执行完毕后,此方法会被调用,参数即为后台任务的返回结果
onCancelled() //此方法会在后台任务被取消时被调用
注意 :
1.AsyncTask对象必须在主线程中创
2.AsyncTask对象的execute方法必须在主线程中调用
3.一个AsyncTask对象只能调用一次execute方法
4. AsyncTask在最早的版本中用一个单一的后台线程串行执行多个AsyncTask实例的任务,从Android 1.6(DONUT)开始,AsyncTask用线程池并行执行异步任务,但是从Android 3.0(HONEYCOMB)开始为了避免并行执行导致的常见错误,AsyncTask又开始默认用单线程作为工作线程处理多个任务。
从Android 3.0开始AsyncTask增加了executeOnExecutor方法,用该方法可以让AsyncTask并行处理任务,该方法的方法签名如下所示:
public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)
- 1
第一个参数表示exec是一个Executor对象,为了让AsyncTask并行处理任务,通常情况下我们此处传入AsyncTask.THREAD_POOL_EXECUTOR
即可,AsyncTask.THREAD_POOL_EXECUTOR
是AsyncTask中内置的一个线程池对象,当然我们也可以传入我们自己实例化的线程池对象。第二个参数params表示的是要执行的任务的参数。
3. AsyncTask 工作流程分析
3.1 AsyncTask 中定义的一些常量
private static final String LOG_TAG = "AsyncTask"; //CPU_COUNT为手机中的CPU核数 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //将手机中的CPU核数加1作为AsyncTask所使用的线程池的核心线程数的大小 private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //将CPU_COUNT * 2 + 1作为AsyncTask所使用的线程池的最大线程数的大小 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE = 1; //实例化线程工厂ThreadFactory,sThreadFactory用于在后面创建线程池 private static final ThreadFactory sThreadFactory = new ThreadFactory() { //mCount为AtomicInteger类型,AtomicInteger是一个提供原子操作的Integer类, //确保了其getAndIncrement方法是线程安全的 private final AtomicInteger mCount = new AtomicInteger(1); //重写newThread方法的目的是为了将新增线程的名字以"AsyncTask #"标识 public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());}; //实例化阻塞式队列BlockingQueue,队列中存放Runnable,容量为128 private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); //根据上面定义的参数实例化线程池 public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); |
通过以上代码和注释我们可以知道,AsyncTask初始化了一些参数,AsyncTask内部维护了一个静态的线程池THREAD_POOL_EXECUTOR,AsyncTask的实际工作就是通过该THREAD_POOL_EXECUTOR
完成的。
另外,还有一个SerialExecutor类型的实例SERIAL_EXECUTOR
,它也是public static final
的。SerialExecutor是AsyncTask的一个内部类。
//SerialExecutor实现了Executor接口中的execute方法,该类用于串行执行任务,即一个接一个地执行任务,而不是并行执行任务 private static class SerialExecutor implements Executor { //mTasks是一个维护Runnable的双端队列,ArrayDeque没有容量限制,其容量可自增长 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); //mActive表示当前正在执行的任务Runnable Runnable mActive; public synchronized void execute(final Runnable r) { //execute方法会传入一个Runnable类型的变量r,然后我们会实例化一个Runnable类型的匿名内部类以对r进行封装, //通过队列的offer方法将封装后的Runnable添加到队尾 mTasks.offer(new Runnable() { public void run() { try { //执行r的run方法,开始执行任务,此处r的run方法是在线程池中执行的 r.run();} finally {//当任务执行完毕的时候,通过调用scheduleNext方法执行下一个Runnable任务 scheduleNext();} }}); //只有当前没有执行任何任务时,才会立即执行scheduleNext方法 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { //通过mTasks的poll方法进行出队操作,删除并返回队头的Runnable,,将返回的Runnable赋值给mActive, //如果不为空,那么就让将其作为参数传递给THREAD_POOL_EXECUTOR的execute方法进行执行 if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } } |
AsyncTask内部定义了一个Status枚举类型,如下所示:
public enum Status {
//PENDING表示还没有开始执行任务
PENDING,
//RUNNING表示已经开始执行任务
RUNNING,
//FINISHED表示任务已经执行完成或被取消了,总之onPostExecute方法已经被调用了
FINISHED,
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
一个AsyncTask正常情况下会经历PENDING->RUNNING->FINISHED三个状态。
AsyncTask还定义了以下字段:
//用于通过Handler发布result的Message Code
private static final int MESSAGE_POST_RESULT = 0x1;
//用于通过Handler发布progress的Message Code
private static final int MESSAGE_POST_PROGRESS = 0x2;
//sDefaultExecutor表示AsyncTask默认使用SERIAL_EXECUTOR作为Executor,
//即默认情况下AsyncTask是串行执行任务,而不是并行执行任务
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//InternalHandler是AsyncTask中定义的一个静态内部类,其绑定了主线程的Looper和消息队列
private static InternalHandler sHandler;
//mWorker是一个实现了Callable接口的对象,其实现了Callable接口的call方法
private final WorkerRunnable<Params, Result> mWorker;
//根据mFuture是一个FutureTask对象,需要用mWorker作为参数实例化mFuture
private final FutureTask<Result> mFuture;
//AsyncTask的初始状态位PENDING
private volatile Status mStatus = Status.PENDING;
//mCancelled标识当前任务是否被取消了
private final AtomicBoolean mCancelled = new AtomicBoolean();
//mTaskInvoked标识当前任务是否真正开始执行了
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
说明 :
sDefaultExecutor表示AsyncTask执行任务时默认所使用的线程池,sDefaultExecutor的初始值为SERIAL_EXECUTOR,表示默认情况下AsyncTask是串行执行任务,而不是并行执行任务。
InternalHandler是AsyncTask中定义的一个静态内部类,其部分源码如下所示:
private static class InternalHandler extends Handler {
public InternalHandler() {
//Looper类的getMainLooper方法是个静态方法,该方法返回主线程的Looper
//此处用主线程的Looper初始化InternalHandler,表示InternalHandler绑定了主线程
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_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
- 17
- 18
- 19
- 20
- 21
- 22
- 23
通过InternalHandler的构造函数我们可以发现,用主线程的Looper初始化了InternalHandler,说明InternalHandler绑定了主线程。后面会讨论InternalHandler的handleMessage方法。
由于AsyncTask能够取消任务,所以AsyncTask使用了FutureTask以及与其相关的Callable。Executor的execute方法接收一个Runnable对象,由于FutureTask实现了Runnable接口,所以可以把一个FutureTask对象传递给Executor的execute方法去执行。当任务执行完毕的时候会执行FutureTask的done方法,在任务执行的过程中,我们也可以随时调用FutureTask的cancel方法取消执行任务,任务取消后也会执行FutureTask的done方法。我们也可以通过FutureTask的get方法阻塞式地等待任务的返回值(即Callable的call方法的返回值),如果任务执行完了就立即返回执行的结果,否则就阻塞式等待call方法的完成。
mFuture是FutureTask类型的对象,mWorker是WorkerRunnable类型的对象,WorkerRunnable是AsyncTask中的一个内部类,代码如下所示
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams;}
由此可以看出WorkerRunnable其实就是一个指定了泛型Result的Callable,所以mWorker也就是一个Callable对象。
mStatus的值为PENDING,表示AsyncTask的初始状态为未执行状态。mCancelled标识当前任务是否被取消了,mTaskInvoked标识当前任务是否真正开始执行了。
下面我们看一下AsyncTask的构造函数:
//AsyncTask的构造函数需要在UI线程上调用
public AsyncTask() {
//实例化mWorker,实现了Callable接口的call方法
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//call方法是在线程池的某个线程中执行的,而不是运行在主线程中
//call方法开始执行后,就将mTaskInvoked设置为true,表示任务开始执行
mTaskInvoked.set(true);
//将执行call方法的线程设置为后台线程级别
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//在线程池的工作线程中执行doInBackground方法,执行实际的任务,并返回结果
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
//将执行完的结果传递给postResult方法
return postResult(result);
}
};
//用mWorker实例化mFuture
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//任务执行完毕或取消任务都会执行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);
}
}
};
}
- 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
在AsyncTask的构造函数中依次实例化了mWorker和mFuture,AsyncTask的构造函数需要在UI线程上调用。下面对以上代码进行一下说明。
mWorker
我们之前提到,mWorker其实是一个Callable类型的对象。实例化mWorker,实现了Callable接口的call方法。call方法是在线程池的某个线程中执行的,
而不是运行在主线程中。在线程池的工作线程中执行doInBackground方法,执行实际的任务,并返回结果。当doInBackground执行完毕后,
将执行完的结果传递给postResult方法。postResult方法我们后面会再讲解。
mFuture
mFuture是一个FutureTask类型的对象,用mWorker作为参数实例化了mFuture。在这里,其实现了FutureTask的done方法,我们之前提到,
当FutureTask的任务执行完成或任务取消的时候会执行FutureTask的done方法。done方法里面的逻辑我们稍后再将。
在实例化了AsyncTask对象之后,我们就可以调用AsyncTask的execute方法执行任务,execute代码如下所示:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
- 1
- 2
- 3
- 4
execute方法有@MainThread
,所以该方法应该在主线程上执行。通过上面代码我们发现,execute方法只是简单调用了executeOnExecutor方法,
并且把sDefaultExecutor作为参数传递给了executeOnExecutor,此处就能看出sDefaultExecutor是默认执行任务的Executor了。
我们再看一下executeOnExecutor方法,其代码如下所示:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
//如果当前AsyncTask已经处于运行状态,那么就抛出异常,不再执行新的任务
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
//如果当前AsyncTask已经把之前的任务运行完成,那么也抛出异常,不再执行新的任务
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
//将AsyncTask的状态置为运行状态
mStatus = Status.RUNNING;
//在真正执行任务前,先调用onPreExecute方法
onPreExecute();
mWorker.mParams = params;
//Executor的execute方法接收Runnable参数,由于mFuture是FutureTask的实例,
//且FutureTask同时实现了Callable和Runnable接口,所以此处可以让exec执行mFuture
exec.execute(mFuture);
//最后将AsyncTask自身返回
return this;
}
下面对以上代码进行一下说明:
1. 一个AsyncTask实例执行执行一次任务,当第二次执行任务时就会抛出异常。executeOnExecutor方法一开始就检查AsyncTask的状态是不是PENDING,
只有PENDING状态才往下执行,如果是其他状态表明现在正在执行另一个已有的任务或者已经执行完成了一个任务,这种情况下都会抛出异常。
2. 如果开始是PENDING状态,那么就说明该AsyncTask还没执行过任何任务,代码可以继续执行,然后将状态设置为RUNNING,表示开始执行任务。
3. 在真正执行任务前,先调用onPreExecute方法。由于executeOnExecutor方法应该运行在主线程上,所以此处的onPreExecute方法也会运行在主线程上,
可以在该方法中做一些UI上的处理操作。
4. Executor的execute方法接收Runnable参数,由于mFuture是FutureTask的实例,且FutureTask同时实现了Callable和Runnable接口,
所以此处可以让exec通过execute方法在执行mFuture。在执行了exec.execute(mFuture)之后,后面会在exec的工作线程中执行mWorker的call方法,
我们之前在介绍mWorker的实例化的时候也介绍了call方法内部的执行过程,会首先在工作线程中执行doInBackground方法,并返回结果,
然后将结果传递给postResult方法。
下面我们看一下postResult方法,代码如下所示:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//通过getHandler获取InternalHandler,InternalHandler绑定主线程
//根据InternalHandler创建一个Message Code为MESSAGE_POST_RESULT的Message
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
//将该message发送给InternalHandler
message.sendToTarget();
return result;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在postResult方法中,通过getHandler获取InternalHandler,InternalHandler绑定主线程。getHandler代码如下所示:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
在得到InternalHandler对象之后,会根据InternalHandler创建一个Message Code为MESSAGE_POST_RESULT的Message,
此处还将doInBackground返回的result通过new AsyncTaskResult<Result>(this, result)
封装成了AsyncTaskResult,
将其作为message的obj属性。
AsyncTaskResult是AsyncTask的一个内部类,其代码如下所示:
//AsyncTaskResult用于发布result或用于发布阶段性的数据
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
//mTask表示当前AsyncTaskResult是哪个AsyncTask的结果
final AsyncTask mTask;
//mData表示其存储的数据
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
//此处的data是可变数组
mTask = task;
mData = data;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在构建了message对象后,通过message.sendToTarget()
将该message发送给InternalHandler,
之后InternalHandler的handleMessage方法会接收并处理该message,如下所示:
public void handleMessage(Message msg) {
//msg.obj是AsyncTaskResult类型
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
//发布最后结果
result.mTask.finish(result.mData[0]);
break;
...
result.mTask.onProgressUpdate(result.mData);
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
msg.obj是AsyncTaskResult类型,result.mTask表示当前AsyncTaskResult所绑定的AsyncTask。
result.mData[0]表示的是doInBackground所返回的处理结果。将该结果传递给AsyncTask的finish方法,finish代码如下所示:
private void finish(Result result) {
if (isCancelled()) {
//如果任务被取消了,那么执行onCancelled方法
onCancelled(result);
} else {
//将结果发传递给onPostExecute方法
onPostExecute(result);
}
//最后将AsyncTask的状态设置为完成状态
mStatus = Status.FINISHED;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
finish方法内部会首先判断AsyncTask是否被取消了,如果被取消了执行onCancelled(result),否则执行onPostExecute(result)方法。
需要注意的是InternalHandler是指向主线程的,所以其handleMessage方法是在主线程中执行的,从而此处的finish方法也是在主线程中执行的,
进而onPostExecute也是在主线程中执行的。
上面我们知道了任务从开始执行到onPostExecute的过程。我们知道,doInBackground方法是在工作线程中执行比较耗时的操作,
这个操作时间可能比较长,而我们的任务有可能分成多个部分,每当我完成其中的一部分任务时,
我们可以在doInBackground中多次调用AsyncTask的publishProgress方法,将阶段性数据发布出去。
publishProgress方法代码如下所示:
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
我们需要将阶段性处理的结果传入publishProgress,其中values是不定长数组,
如果任务没有被取消,就会通过InternalHandler创建一个Message对象,
该message的Message Code标记为MESSAGE_POST_PROGRESS,
并且会根据传入的values创建AsyncTaskResult,将其作为message的obj属性。
然后再将该message发送给InternalHandler,然后InternalHandler会执行handleMessage方法,接收并处理该message,
如下所示:
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
...
case MESSAGE_POST_PROGRESS:
//发布阶段性处理结果
result.mTask.onProgressUpdate(result.mData);
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在handleMessage方法中,当message.what为MESSAGE_POST_PROGRESS时,会执行AsyncTask的onProgressUpdate方法,
该方法是在主线程中执行的。
AsyncTask无论任务完成还是取消任务,FutureTask都会执行done方法,如下所示:
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//任务执行完毕或取消任务都会执行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);
}
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
无论任务正常执行完成还是任务取消,都会执行postResultIfNotInvoked方法。postResultIfNotInvoked代码如下所示:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
//只有mWorker的call没有被调用才会执行postResult方法
postResult(result);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
如果AsyncTask正常执行完成的时候,call方法都执行完了,mTaskInvoked设置为true,并且在call方法中最后执行了postResult方法,
然后进入mFuture的done方法,然后进入postResultIfNotInvoked方法,由于mTaskInvoked已经执行,
所以不会执行再执行postResult方法。
如果在调用了AsyncTask的execute方法后立马就执行了AsyncTask的cancel方法(实际执行mFuture的cancel方法),
那么会执行done方法,且捕获到CancellationException异常,从而执行语句postResultIfNotInvoked(null)
,
由于此时还没有来得及执行mWorker的call方法,所以mTaskInvoked还未false,这样就可以把null传递给postResult方法。
扩展-1 为什么AsyncTask只能执行一次 ?
1. excuteOnExcutor 中对状态进行了判断,如果当前任务的状态是Running 或者finished,直接报异常
2. 线程池中执行的futureTask和callable都是final的,只能初始化一次。
扩展-2 AsyncTask 到底是并行的还是串行的 ?
1. 在AsyncTask默认直接使用 AsyncTask.execute() 执行,使用了SerialExecutor, 代码可以看出来时并行的
2. Android 3.0 中,我们可以使用 AsyncTask.executeOnExecutor( AsyncTask.THIRD_POOL_EXECUTOR,"") 来并行,当然自己定义线程池也可以。
HandlerThread
HandlerThread 继承了Thread,但是内部进行了封装,在run 中通过Looper.prepare()创建消息队列,并通过looper.loop()开始消息循环。
这样就可以使用该looper,创建属于该Tread的Handler,从而和主线程进行通信。
|
HandlerThread的特点
- HandlerThread将loop转到子线程中处理,分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
- 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。
相比多次使用new Thread(){…}.start()这样的方式节省系统资源。
但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。 - HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
- 通过设置优先级就可以同步工作顺序的执行,而又不影响UI的初始化;
IntentService
1. 特点
- 它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类
- 它可以用于在后台执行耗时的异步任务,当任务完成后会自动停止
- 相比于Thread,它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务
- 它内部通过HandlerThread和Handler实现异步操作
- 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作
2. 使用 :extends IntentService,然后必须实现两个方法:一个是构造方法,另外一个就是进行异步处理的方法onHandleIntent(Intent intent) 方法,其参数intent可以附带从activity传递过来的数据。
public class MyIntentService extends IntentService{ public MyIntentService(String name) { super(name); // TODO Auto-generated constructor stub } @Override protected void onHandleIntent(Intent arg0) { // TODO Auto-generated method stub } 然后在主线程中 : Intent intent = new Intent(this,MyIntentService.class); intent.putExtra(“” ,data); intent.putExtra(“”,data); startService(intent); |
3. 源码解析 :
3.1 onCreate方法
|
3.2 onCreate执行完成后,会执行onStartCommand-> onStart,onStart方法中,IntentService通过mServiceHandler的sendMessage
方法发送了一个消息,这个消息将会发送到HandlerThread中进行处理(因为HandlerThread持有Looper对象,
所以其实是Looper从消息队列中取出消息进行处理,然后调用mServiceHandler的handleMessage方法)
|
3.3 ServiceHandler的源码
private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); //IntentService会通过 stopSelf(int startId)方法来尝试停止服务。 // 这里采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务, // 而stopSelf(int startId)会等待所有消息都处理完后才终止服务。 stopSelf(msg.arg1); } } |
protected abstract void onHandleIntent(Intent intent);
onHandleIntent 是抽象方法,必须在子类中进行实现,也就是说子类中实现具体的操作。通过上面一系列的分析可知,
onHandleIntent方法也是一个异步方法。这里要注意的是如果后台任务只有一个的话,onHandleIntent执行完,服务就会销毁,
但如果后台任务有多个的话,onHandleIntent执行完最后一个任务时,服务才销毁。最后我们要知道每次执行一个后台任务就必须启动一次IntentService,
而IntentService内部则是通过消息的方式发送给HandlerThread的,然后由Handler中的Looper来处理消息,而Looper是按顺序从消息队列中取任务的,
也就是说IntentService的后台任务时顺序执行的,当有多个后台任务同时存在时,这些后台任务会按外部调用的顺序排队执行
Android 中的线程池
和Java中的线程池类似,都是为了解决下面的问题设计的:
1.重用已经创建的好的线程,避免频繁创建进而导致的频繁GC
2.控制线程并发数,合理使用系统资源,提高应用性能
3.可以有效的控制线程的执行,比如定时执行,取消执行等
Android中的线程池其实源于Java,Java中和线程有关的东东叫做Executor,Executor本身是一个接口,
这个接口有一个非常有用的实现类叫做ThreadPoolExecutor
1. ThreadPoolExecutor
ThreadPoolExecutor有四个重载的构造方法,我们这里来说说参数最多的那一个重载的构造方法,
这样大家就知道其他方法参数的含义了,如下:
- public ThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue<Runnable> workQueue,
- ThreadFactory threadFactory,
- RejectedExecutionHandler handler)
corePoolSize 线程池中核心线程的数量
maximumPoolSize 线程池中最大线程数量
keepAliveTime 非核心线程的超时时长,当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收。
如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则该参数也表示核心线程的超时时长
unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
workQueue 线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
threadFactory 为线程池提供创建新线程的功能,这个我们一般使用默认即可
handler 拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),
默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。
添加新任务的策略 :
1.execute一个线程之后,如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行
2.execute一个线程之后,如果线程池中的线程数已经达到核心线程数,且workQueue未满,则将新线程放入workQueue中等待执行
3.execute一个线程之后,如果线程池中的线程数已经达到核心线程数但未超过非核心线程数,且workQueue已满,则开启一个非核心线程来执行任务
4.execute一个线程之后,如果线程池中的线程数已经超过非核心线程数,则拒绝执行该任务
2. 常用的线程池 :
2.1 FixedThreadPool是一个核心线程数量固定的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
源码 :
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } |
2.2 CachedThreadPool ->不限大小
CachedTreadPool一个最大的优势是它可以根据程序的运行情况自动来调整线程池中的线程数量
源码 :
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } |
2.3 ScheduledThreadPool
是一个具有定时定期执行任务功能的线程池,
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); } |
使用
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); Runnable runnable = new Runnable(){ @Override public void run() { } }; scheduledExecutorService.schedule(runnable, 3, TimeUnit.SECONDS); |
2.4 SingleThreadExecutor
singleThreadExecutor和FixedThreadPool很像,不同的就是SingleThreadExecutor的核心线程数只有1
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } |
参考博客 :
http://blog.csdn.net/iispring/article/details/50670388
https://www.jianshu.com/p/e9b2c0831b0d
http://blog.csdn.net/javazejian/article/details/52426425