一 . AsyncTask

Android的Lazy Load主要体现在网络数据(图片)异步加载、数据库查询、复杂业务逻辑处理以及费时任务操作导致的异步处理等方面。在介绍Android开发过程中,异步处理这个常见的技术问题之前,我们简单回顾下Android开发过程中需要注意的几个地方。

Android应用开发过程中必须遵循单线程模型(Single Thread Model)的原则。因为Android的UI操作并不是线程安全的,所以涉及UI的操作必须在UI线程中完成。但是并非所有的操作都能在主线程中进行,Google工程师在设计上约定,Android应用在5s内无响应的话会导致ANR(Application Not Response),这就要求开发者必须遵循两条法则:

1、不能阻塞UI线程,

2、确保只在UI线程中访问Android UI工具包。于是,开启子线程进行异步处理的技术方案应运而生

二   首先看一到AsyncTask的大纲视图

AsyncTask异步加载的源码分析与实现实例_android

我们可以看到关键几个步骤的方法都在其中,

2.1 doInBackground(Params... params)是一个抽象方法,我们继承AsyncTask时必须覆写此方法;

2.2 onPreExecute()、onProgressUpdate(Proess... values)、onPostExecute(Result result)、onCancelled()这几个方法体都是空的,我们需要的时候可以选择性的覆写它们;

2.3 publishProgress(Progress... values)是final修饰的,不能覆写,只能去调用,我们一般会在doInBackground(Params... params)中调用此方法;

2.4 我们可以看到有一个Status的枚举类和getStatus()方法,Status枚举类代码段如下

//初始状态
private volatile Status mStatus = Status.PENDING;
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
/**
* Returns the current status of this task.
*
* @return The current status.
*/
public final Status getStatus() {
return mStatus;
}

2.4.1           AsyncTask的初始状态为PENDING,代表待定状态,

        RUNNING代表执行状态,

FINISHED代表结束状态,

这几种状态在AsyncTask一次生命周期内的很多地方被使用,非常重要

3 执行过程分析

3.1 一些变量声明的常识

public abstract class AsyncTask<Params, Progress, Result> {
//线程数据标签
private static final String LOG_TAG = "AsyncTask";
//动态获取不同cpu允许开启的线程个数

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//允许开启的最大的线程个数
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;<span style="font-family: Helvetica, Tahoma, Arial, sans-serif; font-size: 14px; line-height: 25.2px;">// 当线程数大于核心时,终止当前多余的空闲线程等待新任务的最长时间10</span>

private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);

public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};


3.2 从 execute作为入口,进行分析执行过程

源码中:

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

调用 executeOnExecutor()方法

3.3 executeOnExecutor()方法

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
//如果该任务正在被执行则抛出异常,值得一提的是,在调用cancel取消任务后,状态仍未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)");
}
}
//改变状态为RUNNING</span>
mStatus = Status.RUNNING;

//调用onPreExecute方法
onPreExecute();


mWorker.mParams = params;

exec.execute(mFuture);

return this;
}

代码中涉及陌生的变量:mWorker、mFuture

3.4关于exec,它是java.util.concurrent.ThreadPoolExecutor的实例,用于管理线程的执行

public interface Executor {

/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}


mWorker实际上是AsyncTask的一个的抽象内部类的实现对象实例,它实现了Callable<Result>接口中的call()方法,

而mFuture实际上是java.util.concurrent.FutureTask的实例,下面是它的FutureTask类的相关信息

/**
* A cancellable asynchronous computation.
* ...
*/
public class FutureTask<V> implements RunnableFuture<V> {


private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}



/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(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);
}
}
};
}


private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}





4 概述

当我们调用execute(Params... params)方法后,execute方法会调用executeOnExecutor()方法,

然后由Executor实例执行一个execute任务,

这个过程中doInBackground(Params... params)将被调用,

如果被开发者覆写的doInBackground(Params... params)方法中调用了publishProgress(Progress... values)方法,

则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress... values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

经过上面的介绍,相信朋友们都已经认识到AsyncTask的本质了,它对Thread+Handler的良好封装,减少了开发者处理问题的复杂度,提高了开发效率

5 实例



AsyncTask异步加载的源码分析与实现实例_ide_02



import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
* AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然可以看到Thread和Handler的踪迹
*/

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

/**
* 初始化所有的控件
*/
assignViews();

/**
* 为按钮设置点击事件
*/
setButtonOnClick();

}

private TextView mTextView01;
private ProgressBar mProgressBar02;
private Button mButton03;

private void assignViews() {
mTextView01 = (TextView) findViewById(R.id.textView01);
mProgressBar02 = (ProgressBar) findViewById(R.id.progressBar02);
mButton03 = (Button) findViewById(R.id.button03);
}

private void setButtonOnClick() {
mButton03.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 调用
*/
ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(mTextView01, mProgressBar02);
asyncTask.execute(1000);
}
});
}

/**
* AsyncTask直接继承于Object类,位置为android.os.AsyncTask
* AsyncTask定义了三种泛型类型 Params,Progress和Result
* Params 启动任务执行的输入参数,比如HTTP请求的URL
* Progress 后台任务执行的百分比
* Result 后台执行任务最终返回的结果,比如String
*onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
*onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
*onCancelled() 用户调用取消时,要做的操作
*Task的实例必须在UI thread中创建;
*execute方法必须在UI thread中调用
*/
class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {

private TextView textView;
private ProgressBar progressBar;

/**
* 构造方法
* @param textView
* @param progressBar
*/
public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {
super();
this.textView = textView;
this.progressBar = progressBar;
}

//该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
@Override
protected void onPreExecute() {
textView.setText("开始执行异步线程");
}
/**
* 这里的Integer参数对应AsyncTask中的第一个参数
* 这里的String返回值对应AsyncTask的第三个参数
* 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
* 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
*/
@Override
protected String doInBackground(Integer... params) {

int i = 0;
for (i = 10; i <= 100; i += 10) {
SystemClock.sleep(800);
publishProgress(i);
}
return i + params[0].intValue() + "";
}


/**
* 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
* 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
*/
@Override
protected void onPostExecute(String result) {
textView.setText("异步操作执行结束" + result);
}


/**
* 这里的Intege参数对应AsyncTask中的第二个参数
* 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
* onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
*/
@Override
protected void onProgressUpdate(Integer... values) {
if (BuildConfig.DEBUG) Log.d("ProgressBarAsyncTask", "onprogressupdate");
int vlaue = values[0];
progressBar.setProgress(vlaue);
}

/**
* 用户调用取消时,要做的操
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
}
}