赞
踩
线程是Android的一个重要概念,从用途来说,线程分为主线程和子线程。
线程 | 作用 |
---|---|
主线程 | 进程所拥有的线程,在Java中默认情况下一个进程只有一个线程,即为主线程。主线程主要处理界面交互相关的逻辑,在任何时候都必须有较高的响应速度,因此主线程中不能执行耗时任务 |
子线程 | 也叫工作线程,用于执行耗时操作,除了主线程之外的线程都是子线程 |
Android沿用了Java的线程模型,其中的线程也分为主线程和子线程,其中主线程也叫UI线程。主线程作用是运行四大组件以及处理它们和用户的交互,子线程作用则是执行耗时任务,例如网络请求、I/O操作等。
Android中的线程形态除了传统的Thread之外,还包含了AsyncTask、HandlerThread以及IntentService,这三者的底层实现也是线程。
线程形态 | 描述 |
---|---|
AsyncTask | 封装了线程池和Handler,主要是为了方便开发者在子线程中更新UI |
HandlerThread | 具有消息循环的线程,内部可以使用Handler |
IntentService | 内部采用HandlerThread执行任务,任务执行完毕自动退出 |
AsyncTask的描述可以总结为:
AsyncTask的5个核心方法如下表所示。具体是使用方法可以参考笔者的笔记:Android基础知识(十一):AsyncTask原理与使用简介。
方法 | 含义 |
---|---|
onPreExecute() | 主线程中执行,在异步任务执行之前被调用,一般可以用于做一些准备工作 |
doInBackground(Params… params) | 在线程池中执行,用于执行异步任务,params表示异步任务的输入参数。可通过调用publishProgress方法更新任务进度,publishProgress会调用onProgressUpdate方法。此外,该方法返回结果给onPostExecute方法。 |
onProgressUpdate(Progress… values) | 在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用 |
onPostExecute(Result result) | 主线程中执行,异步任务执行之后被调用,result为后台任务doInBackground返回值 |
onCancelled() | 主线程中执行,异步任务被取消时调用,此时onPostExecute不会被调用 |
AsyncTask的具体使用过程有一些条件限制:
① AsyncTask的类必须在主线程中加载,这意味着AsyncTask第一次访问必须发生在主线程中。在Android 4.1及以上版本系统已自动完成——ActivityThread的main方法。
② AsyncTask的对象必须在主线程中创建。
③ execute方法必须在UI线程中调用。
④ 不要在程序中直接调用onPreExecute()、onPostExecute()、doInBackground()和onProgressUpdate()方法。
⑤ 一个AsyncTask对象只能执行一次,即只能调用一次excute方法,否则会报运行时异常。
⑥ 在Android 1.6之前,AsyncTask是串行执行任务的,Android 1.6的时候开始采用线程池处理并行任务。但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,又采用一个线程来串行执行任务,但是可以通过excuteOnExecutor方法来并行执行方法。
接下来分析AsyncTask的工作原理,从execute方法开始分析,execute方法又会调用executeOnExecutor方法。
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; }
其中sDefaultExecutor是一个串行的线程池,一个进程中的所有的AsyncTask在该线程池中排队执行。从上面代码可以看到,AsyncTask先执行onPreExecute方法,然后线程池开始执行。
@UnsupportedAppUsage private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new 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); } } }
从SerialExecutor的实现分析AsyncTask的排队执行过程。首先系统会把AsyncTask的Params参数封装成FutureTask(并发类,充当Runnable作用)对象mFuture。接着mFuture交给SerialExecutor的excute方法处理,该方法把mFuture插入到任务队列mTasks中,如果这个时候没有正在活动的AsyncTask任务,那么会调用scheduleNext方法执行下一个任务。当一个任务执行完,AsyncTask会继续执行其他任务直到所有任务被执行为止,这也就是其串行执行的原因。
AsyncTask中有两个线程池和一个Handler,如下表所示。
组成 | 描述 |
---|---|
SerialExecutor | 用于任务的排队 |
THREAD_POOL_EXECUTOR | 用于真正地执行任务 |
InternalHandler | 用于将执行环境从线程池切换到主线程 |
由于FutureTask的run方法会调用mWorker的call方法,因此call方法会在线程池执行。
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; } };
在mWorker的call方法中,mTaskInvoked设置为true,表示当前任务已经被调用,然后执行AsyncTask的doInBackground方法,将其返回值传递给postResult方法。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
在上面代码中,postResult方法会通过sHandler发送一个MESSAGE_POST_RESULT的消息。
private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @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; } } }
sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这要求sHandler这个对象必须在主线程中创建。由于静态成员会在加载类的时候进行初始化,这变相要求在主线程中加载。
sHandler收到MESSAGE_POST_RESULT消息之后,调用finish方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
从上面代码也可以看到,如果AsyncTask被取消执行,会调用onCancelled方法,否则调用onPostExecute方法,并且会传递doInBackground的返回结果。
以上就是AsyncTask的整个工作原理过程。
HandlerThread继承了Thread,是一种可以使用Handler的Thread。其实现比较简单易理解,在run方法中通过Looper.prepare()创建消息队列,并通过Looper.loop()开启消息循环。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
与普通Thread不同之处在于,HandlerThread在内部创建了消息队列,外界需要通过Handler的消息方式通知HandlerThread执行任务。由于HandlerThread的run方法是无限循环,因此使用的时候需要通过quit或者quitSafely方法终止线程。
IntentService的特点可以总结为如下几点:
在实现上,从onCreate方法可以看出,IntentService封装了HandlerThread和Handler。
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在onCreate中,创建了HandlerThread,并其Looper构造Handler,这样通过mServiceHandler发送的消息会在HandlerThread中执行,即后台执行。
每次启动IntentService其onStartCommand方法被调用,从而处理每个后台任务的Intent,而该方法调用了onStart方法。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看出,IntentService只是通过mServiceHandler发送消息,这个消息会在HandlerThread线程中处理,处理方式具体看ServiceHandler的源码。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
handleMessage方法先调用onHandleIntent方法处理后台任务,之后通过stopSelf(startId)尝试停止服务,这就是其能够自动停止的原因。而Service可以使用stopSelf()停止服务,为何不用该方法呢?
这两个方法的区别具体看下表。
方法 | 描述 |
---|---|
stopSelf() | 立刻停止服务,这个时候可能还有其他消息未处理 |
stopSelf(startId) | 等待所有消息都处理完毕后才终止服务。在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,相等则停止,否则不停止 |
因此,从逻辑上来说,使用stopSelf(startId)才能处理完所有消息。另外,onHandleIntent方法是抽象方法,需要子类实现。
由于每执行一次后台任务就必须启动一次IntentService,而Looper是顺序处理消息的,这就意外着IntentService也是顺序执行后台任务的。
关于IntenService的使用可以参见笔记:Android基础知识(十三):Service生命周期及更多技巧。
参考资料:《Android艺术开发探索》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。