一:概述
关于Android异步处理:
常用异步处理
- runOnUiThread
- AsyncTask
- Handler
- HandlerThread
- IntentService
这次blog主要分析除Handler之外的其他异步消息处理机制,关于Handler的分析详见上一篇bloghttps://blog.youkuaiyun.com/qq_40834350/article/details/101099981
关于以上各种基础用法在此不做说明,默认已经会熟练使用。
二:源码分析部分
runOnUiThread:
源码如下:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
可以看到,此函数会先判断当前线程是否运行在UI线程,若运行在UI Thread,则action会立即运行;否则,改action就被handlerpost到UI线程的事件队列中,关于Handler的部分此处不做解释。
AsyncTask:
我们由一段Google官方示例程序为入口分析:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
new DownloadFilesTask().execute(url1, url2, url3);
关于AsyncTask的使用注意事项
-
AsyncTask 类需要 UI 线程中加载,在 Android 4.1 以上版本,这个加载过程已经由系统来完成了
-
AsyncTask 实例需要 UI 线程中创建
-
execute 方法必须在 UI 线程中被调用
-
不要直接调用 AsyncTask 的四个复写方法:onPreExecute、onPostExecute、onProgressUpdate、doInBackground
-
一个 AsyncTask 实例,只能调用一次,重复调用会报错,也就是说,如果想再次调用 AsyncTask,需要重新创建实例
可以看到,当完成AsyncTask实现类的编写后,DownloadFilesTask.execute()方法开始执行任务
让我们进入此方法内部:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
从此代码中,我们可以知道,execute()又将任务交给executeOnExecutor()方法去执行,但是参数中有一个sDefaultExecutor,我们来查看相关声明代码:
import java.util.concurrent.Executor;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
Java Executor作为一个灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程进行了解耦开发,基于生产者和消费者模型,还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能检测等机制。更多详细的使用与深入理解请读者自行百度。
接下来,我们进入executeOnExecutor()查看:
@MainThread
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;
}
表明 AsyncTask 运行状态用一个 Status 的枚举来表示,有三种状态 PENDING --> RUNNING --> FINISHED。当创建 AsyncTask 后,表示运行状态的变量 mStatus 初始化为 Status.PENDING,执行开始后为 RUNNING,执行结束后更改为 FINISHED,中间过程不能修改为之前的状态。分析executeOnExecutor,先进行状态的判断,若处于可执行状态,则将状态置为RUNNING。然后调用onPreExecute
方法,交给用户进行执行任务前的准备工作。核心部分在于 exec.execute(mFuture)
。
线程开始执行前 onPreExecute() 得到执行,根据我们所知onPreExecute() 应该在主线程中被调用,所以execute同时也就需要运行在主线程中。
接着是开始执行子线程任务,这里有两个变量,此处涉及到了mWorker, mFuture,让我们来看他们在类中的实现:
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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;
}
};
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);
}
}
};
}
可以看出,mWorker 封装了Callable ,添加了参数 mParams和Result,内部传递到 doInBackground(Params... params) 方法。从finally块中的postResult()方法也可以知道此函数为doBackground()方法执行的返回参数进行了调用,将结果发送给UI线程。
mFuture 对 mWorker 进行包装,它能够在线程执行完获取结果,同时也能够知道线程是否被取消,如果 mWorker 的 call 方法因为异常没有被执行时(即 mTaskInvoked.get() 为 false 时),也能够通知到主线程。
然后,我们可以看看postResultIfNoInvoked()方法,同时我也给出了postResult()方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
关于Hander所处理的消息,我们从这里查看:
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;
}
}
}
关于onProgressUpdate的方法执行,我们可以从publishProgress方法中看到,正是它向handler发送的MESSAGE_POST_PROGRESS类型消息。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
finish()方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
关于onPostExecute()方法,则是运行在主线程中,从上述finish方法中可以得知调用了此方法:
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
我们知道了mWorker,mFuture,同时根据之前的代码知道执行过程中使用的 AsyncTask 的默认执行器 sDefaultExecutor,所有的 AsyncTask 的任务都是通过它来执行的。所有有必要深入分析它的代码:
import java.util.concurrent.Executor;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
我们看到mFuture是插入到mTasks任务队列的对象,若一个AsyncTask任务执行完毕,则继续执行下一个AsyncTask任务,直至所有任务执行完毕。通过分析发现真正去执行后台任务的是线程池THREAD_POOL_EXECUTOR。
下面是它的源码:
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
现在我们可以知道,mFuture为线程池执行的真正任务,根据之前mFuture的分析我们就知道了mFuture做了些什么。
至此,我们算是浅显的分析了AsyncTask的源码,更多深入分析需要更多时间精力取思考。
HandlerThread:
这里给出一个简单的示例:
// 1:创建HandlerThread对象
HandlerThread mHandlerThread = new HandlerThread("handlerThread");
// 2:启动线程
mHandlerThread.start();
// 3:创建工作线程Handler并重写handleMessage()
// 注:handlerMessage()的执行线程与mHandlerThread创建线程相同
Handler workHandler = new Handler( handlerThread.getLooper() ) {
@Override
public boolean handleMessage(Message msg) {
...//消息处理
return true;
}
});
// 4:使用工作线程Handler向工作线程的消息队列发送消息
// a. 定义要发送的消息
Message msg = Message.obtain();
msg.what = 2; //消息的标识
msg.obj = "B"; // 消息的存放
// b. 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
// 步骤5:结束线程,即停止线程的消息循环
mHandlerThread.quit();
可以看到HandlerThread的使用主要由5个部分,代码中已经给出相应注解。
接下来就可以查看它的源码实现(给出主要部分):
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
//省略构造方法...
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
......
}
读者可以自行分析,此处就不进行深入分析,推荐Carson_Ho的文章https://blog.youkuaiyun.com/carson_ho/article/details/52693418
IntentService:
IntentService是一个基础类,用于处理Intent类型的异步任务请求。当客户端调用startService(Intent)发送请求时,Service服务被启动,且在其内部构建一个工作线程来处理Intent请求。当工作线程执行结束,Service服务会自动停止。IntentService是一个抽象类,用户必须实现一个子类去继承它,且必须实现IntentService里面的抽象方法onHandleIntent来处理异步任务请求。
Service服务是Android四大组件之一,在Android中有着很重要的作用。Service服务是工作的UI线程中,当我们处理一些无关UI但是需要长期执行的任务时,一般的用法都是Service+Thread。可是每次都是如此的方式,显得很麻烦,没必要每次都去构建一个Service+Thread框架处理长期处于后台的任务。所以就有了上面描述的IntentService。
同样,我们从一段示例程序进入分析:
public class MyIntentService extends IntentService {
public MyIntentService(){
super("MyIntentService");
}
/**
* 实现异步任务的方法
* @param intent Activity传递过来的Intent,数据封装在intent中
*/
@Override
protected void onHandleIntent(Intent intent) {
//处理任务
......
}
}
}
MyIntentService类中,并没有创建Thread线程去执行异步耗时任务请求。所有的异步耗时任务都是在onHandleIntent抽象方法中实现了。我们只需实现其中的onHandleIntent抽象方法去处理异步任务即可。加下来我们一步步分析IntentService:
首先,关于他的构造函数源码如下:
public IntentService(String name) {
super();
mName = name;
}
此构造方法没有什么负责之处,参数name用于定义工作线程的名称,仅仅用于调式作用。下面就按照Service的周期生命方法进行分析:首先就是我们熟知的onCreate()方法:
@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);
}
该方法首先利用HandlerThread类创建了一个循环的工作线程thread,然后将工作线程中的Looper对象作为参数来创建ServiceHandler消息执行者。关于HandlerThread见上一部分。
接下来是onStartCommand():
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
可以看到还是调用了onStart()方法:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
该方法中通过mServiceHandler获得一个消息对象msg,然后将startId作为该消息的消息码,将异步任务请求intent作为消息内容封装成一个消息msg发送到mServiceHandler消息执行者中去处理,所以接下来关注mServiceHandler的实现:
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);
}
}
ServiceHandler是IntentService的内部类,在重写消息处理方法handlerMessage里面调用了onHandlerIntent抽象方法去处理异步任务intent的请求,当异步任务请求结束之后,调用stopSelf方法自动结束IntentService服务。当然此处handleMessage方法是在工作线程中调用的,因此我们子类重写的onHandlerIntent也是在工作线程中实现的。所来来看onHandlerIntent方法:
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
此方法处理intent异步任务请求,运行在工作线程。当同时又多个intent请求时,其他的intent请求会暂时被挂起,直到前面的intent异步任务请求处理完成才会处理下一个intent请求。直到所有的intent请求结束之后,IntentService服务会调用stopSelf停止当前服务。也就是当intent异步任务处理结束之后,对应的IntentService服务会自动销毁,进而调用IntentService#onDestroy方法:
@Override
public void onDestroy() {
mServiceLooper.quit();
}
该方法调用Looper对象的quit方法让当前工作线程HandlerThread退出当前Looper循环,结束线程。最后结束当前IntentService服务。
以上就是几种常见的异步消息处理机制的部分源码,当然关于更深入和全面的分析,我也会努力学习。