Android AsyncTask的工作原理

1 AsyncTask的基本使用

public abstract class AsyncTask<Params, Progress, Result> 
  • Params:启动任务执行的输入参数,如http请求的url

  • Progress:后台任务执行的百分比

  • Result:后台执行任务最终返回的结果类型

对应参数不处理设置成Void

public class DownLoadAsyncTask extends AsyncTask<String,Integer,Bitmap> {

    /**
     * onPreExecute是可以选择性覆写的方法
     * 在主线程中执行,在异步任务执行之前,该方法将会被调用
     * 一般用来在执行后台任务前对UI做一些标记和准备工作,
     * 如在界面上显示一个进度条。
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    /**
     * 抽象方法必须覆写,执行异步任务的方法
     * @param params
     * @return
     */
    @Override
    protected Bitmap doInBackground(String... params) {
        return null;
    }

    /**
     * onProgressUpdate是可以选择性覆写的方法
     * 在主线程中执行,当后台任务的执行进度发生改变时,
     * 当然我们必须在doInBackground方法中调用publishProgress()
     * 来设置进度变化的值
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    /**
     * onPostExecute是可以选择性覆写的方法
     * 在主线程中执行,在异步任务执行完成后,此方法会被调用
     * 一般用于更新UI或其他必须在主线程执行的操作,传递参数bitmap为
     * doInBackground方法中的返回值
     * @param bitmap
     */
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
    }

    /**
     * onCancelled是可以选择性覆写的方法
     * 在主线程中,当异步任务被取消时,该方法将被调用,
     * 要注意的是这个时onPostExecute将不会被执行
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
    }
}

启动AsyncTask:

new DownLoadAsyncTask().execute();

AsyncTask在具体的使用过程中也是有一些条件限制的,主要有如下几点:

  • AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1及以上版本中已经被系统自动完成。在Android 5.0的源码中,可以查看 ActivityThreadmain 方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了

  • AsyncTask的对象必须在主线程中创建

  • execute()必须在UI线程调用

  • 不要在程序中直接调用 onPreExecute()onPostExecute()doInBackground()onProgressUpdate()

  • 一个AsyncTask对象只能执行一次,即只能调用一次 execute(),否则会报运行时异常

  • 在Android 1.6之前,AsyncTask是串行执行任务,Android 1.6的时候AsyncTask开始采用线程池处理并行任务,但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用了一个线程来串行执行任务。尽管如此,在Android 3.0以及后续版本中,仍然可以通过AsyncTask的 executeOnExecutor() 来并行执行任务

3 AsyncTask工作原理

为了能够更清晰的理解AsyncTask的工作原理,在分析原理之前,有必要对AsyncTask的内部构造做一个简单的说明。

我们知道AsyncTask能在 doInBackground() 执行耗时操作,其中耗时操作会由内部的一个线程池 THREAD_POOL_EXECUTOR 处理, onProgressUpdate()onPostExecute() 切回主线程更新UI,而切换回UI线程是通过Handler收发消息实现的。

execute() 开始分析,execute() 会调用 executeOnExecutor()

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
	// sDefaultExecutor是一个串行的线程池
	// 一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行
	return executeOnExecutor(sDefaultExecutor, params);
}

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
	if (mStatus != Status.PENDING) {
		switch (mStatus) {
			case RUNNING:
			case FINISHED:
				// 抛异常
				break;
		}
	}
	mStatus = Status.RUNNING;
	onPreExecute(); // 在执行耗时操作前就回调onPreExecute()
	mWorker.mParams = params; // WorkerRunnable的call()方法会在线程池中执行回调doInBackground()
	exec.execute(mFuture); // FutureTask,在构造中会传入在线程池执行耗时任务的mWorker
	return this;
}

接下来分析线程池的执行过程:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

// SerialExecutor线程池用于任务的排队,实际执行的线程池是THREAD_POOL_EXECUTOR
private static class SerialExecutor implements Executor {
	final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();
	Runnable mActive;

	// 在AsyncTask.executorOnExecutor()中的sDefaultExecutor.execute()调用该方法
	// 传入的是AsyncTask的Params参数封装的FuterTask对象,是一个并发类充当Runnable
	public synchronized void execute(final Runnable r) {
		// 将Runnable存到队列中
		mTasks.offer(new Runnable() {
			public void run() {
				try {
					// 从这里可以看出在一个AsyncTask任务执行完后才去拿下一个AsyncTask任务
					// 调用FuterTask的run(),实际是调用的内部WorkerRunnable的call()
					r.run();
				} finally {
					scheduleNext(); // 执行下一个AsyncTask任务
				}
			}
		});
		if (mActive == null) {
			scheduleNext();
		}
	}

	protected synchronized void scheduleNext() {
		// 从队列中拿一个AsyncTaskr任务扔给线程池执行
		if ((mActive == mTasks.poll()) != null) {
			// 实际的耗时操作是在线程池THREAD_POOL_EXECUTOR执行
			THREAD_POOL_EXECUTOR.execute(mActive); 
		}
	}
}

FutureTaskrun() 会调用 mWorkercall() 方法,因此 mWorkercall() 最终会在线程池中执行,在AsyncTask构造方法中:

mWorker = new WorkerRunnable<Params, Result>() {
	public Result call() throws Exception {
		mTaskInvoked.set(true); // 设置标志表示当前任务已经被调用了

		Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
		return postResult(doInBackground(mParams));
	}
};

mFuter = new FuterTask<Result>(mWorker) {...}

private Result postResult(Result result) {
	Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 
		new AsyncTaskResult<Result>(this, result));
	message.sendToTarget(); // 将doInBackground()的执行结果通过Handler发送切换回主线程更新UI
	return result;
}

private static final InternalHandler sHandler = new InternalHandler();

// 在线程池中获取的数据通过Handler从子线程切换回主线程更新UI
// InternalHandler是静态成员在加载类的时候会初始化,因此这就要求AsyncTask必须在主线程中加载
private static class InternalHandler extends Handler {
	@Override
	public void handleMessage(Message msg) {
		AsyncTaskResult result = (AsyncTaskResult) msg.obj;
		switch (msg.what) {
			case MESSAGE_POST_RESULT:
				result.mTask.finish(result.mData[0]); // 回调AsyncTask的finish
				break;
			case MESSAGE_POST_PROGRESS:
				result.mTask.onProgressUpdate(result.mData);
				break;	
		}
	}
}

private void finish(Result result) {
	if (isCancelled()) {
		onCancelled(result);
	} else {
		onPostExecute(result); // 回调结果
	}
	mStatus = Status.FINISHED;
}

// FutureTask内部
public FutureTask(Runnable runnable) {
	this.callable = callable;
	this.state = NEW;
}

public void run() {
	try {
		Callable<V> c = callable;
		if (c != null && state == NEW) {
			V result;
			try {
				result = c.call(); // 调用的是WorkerRunnable的call()
			} catch (Throwable ex) {...}
		}
	} finally {...}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值