在android应用开发过程中,我们需要是时刻注意保证应用程序的稳定和UI操作响应及时,不稳定或响应不及时会带来不好的用户体验。
那么为何要引入AsyncTask?
在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但一个进程中可以有多个线程。
在这些线程中,有一个线程叫做UI线程(也叫Main Thread),除了UI线程外的线程都叫子线程(Worker Thread)。UI线程主要负责控制UI界面的显示、更新、交互等。因此,UI线程中的操作延迟越短越好(流畅)。把一些耗时的操作(网络请求、数据库操作、逻辑计算等)放到单独的线程,可以避免主线程阻塞。那么问题来了,如何实现这种异步方式呢?
Android给我们提供了一种轻量级的异步任务类AsyncTask。该类中实现异步操作,并提供接口反馈当前异步执行结果及进度,这些接口中有直接运行在主线程中的(如 onPostExecute,onPreExecute等)。
就结合AndroidAPI文档开发文档解说一下AsyncTask:
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");
}
}
Once created, a task is executed very simply:
new DownloadFilesTask().execute(url1, url2, url3);
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
//在执行时发送到任务的参数类型。
2.Progress, the type of the progress units published during the background computation.
//进度,后台计算过程中的进度单位类型,实现进度条,其中publishProgress()中的参数对应onProgressUpdate()中的参数。
3.Result, the type of the result of the background computation.
//此结果是doInBackground返回的结果,而接收的方法为onPostExecute()而result参数即为返回来的参数
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
//异步任务总是使用并非所有类型。 要将类型标记为未使用,只需使用类型Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }1.onPreExecute()在执行任务之前在UI线程上调用。此步骤通常用于设置任务,例如通过在用户界面中显示进度条。
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
1.onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
2.doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
3.onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
4.onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
当执行异步任务时,任务将通过4个步骤:
1.onPreExecute()在执行任务之前在UI线程上调用。此步骤通常用于设置任务,例如通过在用户界面中显示进度条。
2.doInBackground(Params ...),在onPreExecute()完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数被传递到此步骤。计算结果必须由此步骤返回,并返回到最后一步。此步骤还可以使用publishProgress(Progress ...)发布一个或多个进度单位。这些值在UI线程上,在onProgressUpdate(Progress ...)步骤中发布。
3.onProgressUpdate(Progress ...),在调用publishProgress(Progress ...)后在UI线程上调用。执行时间未定义。该方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。例如,它可以用于对进度条进行动画处理或在文本字段中显示日志。
4.onPostExecute(Result),在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递给该步骤。
取消任务
任何时候可以通过调用cancel(boolean)来取消任务。调用此方法将导致对isCancelled()的后续调用返回true。调用此方法后,onCancelled(Object),而不是onPostExecute(Object)将在doInBackground(Object [])返回后被调用。为了确保尽快取消任务,您应该始终从doInBackground(Object [])定期检查isCancelled()的返回值(如果可能的话)。
线程规则
有一些线程规则必须遵循这个类才能正常工作:
必须在UI线程上加载AsyncTask类。自动执行JELLY_BEAN。
必须在UI线程上创建任务实例。
必须在UI线程上调用execute(Params ...)。
不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params ...),onProgressUpdate(Progress ...)。
该任务只能执行一次(如果尝试第二次执行,将抛出异常)。
记忆可观察性
AsyncTask保证所有回调调用都是同步的,使得以下操作在没有显式同步的情况下是安全的。
在构造函数或onPreExecute()中设置成员字段,并在doInBackground(Params ...)中引用它们。
在doInBackground(Params ...)中设置成员字段,并在onProgressUpdate(Progress ...)和onPostExecute(Result)中引用它们。
执行顺序
当首次引入时,AsyncTasks在单个后台线程上串行执行。从DONUT开始,这被更改为允许多个任务并行操作的线程池。从HONEYCOMB开始,任务在单个线程上执行,以避免并行执行引起的常见应用程序错误。
如果您真的要并行执行,可以使用THREAD_POOL_EXECUTOR调用executeOnExecutor(java.util.concurrent.Executor,Object [])。