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工具包。于是,开启子线程进行异步处理的技术方案应运而生
我们可以看到关键几个步骤的方法都在其中,
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一次生命周期内的很多地方被使用,非常重要
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()); } };
源码中:
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }调用 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); } }
当我们调用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的良好封装,减少了开发者处理问题的复杂度,提高了开发效率
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(); } } }