文档说
处理程序
处理程序允许您发送和处理与线程的 MessageQueue 关联的 Message 和 Runnable 对象。
每个 Handler 实例都与单个线程和该线程的消息队列相关联。
当您创建一个新的处理程序时,它会绑定到创建它的线程的线程/消息队列——从那时起,它会将消息和可运行对象传递到该消息队列并在它们出来时执行它们的消息队列。
处理程序有两个主要用途:(1) 调度消息和在未来某个时间点执行的可运行文件; (2) 将要在与您自己的线程不同的线程上执行的操作排入队列。
调度消息是通过post, postAtTime(Runnable, long), postDelayed, sendEmptyMessage, sendMessage, sendMessageAtTime, and sendMessageDelayed 方法完成的。
post 版本允许您将 Runnable 对象排入队列,以便在收到消息队列时调用它们; sendMessage 版本允许您将包含一组数据的 Message 对象排入队列,这些数据将由 Handler 的 handleMessage 方法处理(要求您实现 Handler 的子类)。
当发布或发送到处理程序时,您可以允许在消息队列准备好后立即处理项目,或者指定处理之前的延迟或处理它的绝对时间。
后两者允许您实现超时、滴答声和其他基于时间的行为。
当为您的应用程序创建进程时,其主线程专用于运行消息队列,该消息队列负责管理顶级应用程序对象(活动、广播接收器等)以及它们创建的任何窗口。
您可以创建自己的线程,并通过处理程序与主应用程序线程返回。
这是通过调用与以前相同的 post 或 sendMessage 方法来完成的,但来自您的新线程。
给定的 Runnable 或 Message 将被调度在 Handler 的消息队列中,并在适当的时候进行处理。
异步任务
AsyncTask 允许正确且轻松地使用 UI 线程。
此类允许在 UI 线程上执行后台操作和发布结果,而无需操作线程和/或处理程序。
AsyncTask 被设计为围绕 Thread 和 Handler 的辅助类,并不构成通用线程框架。
AsyncTasks 最好用于短时间的操作(最多几秒钟。)
如果您需要保持线程长时间运行,强烈建议您使用 java.util.concurrent 包提供的各种 API,例如 Executor、ThreadPoolExecutor 和 FutureTask。
异步任务由在后台运行的计算线程定义,其结果发布在 UI线程上。
异步任务由 3 个通用类型定义,称为 Params、Progress 和 Result,以及 4 个步骤,称为 onPreExecute、doInBackground、onProgressUpdate 和 onPostExecute。
用法
AsyncTask 必须子类化才能使用。
子类将覆盖至少一个方法 (doInBackground),并且通常会覆盖第二个方法 (onPostExecute。)
这是一个子类化的例子:
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");
}
}
一旦创建,任务就会非常简单地执行:
新的 DownloadFilesTask().execute(url1, url2, url3);
AsyncTask 的泛型类型
异步任务使用的三种类型如下:
Params,执行时发送给任务的参数类型。
Progress,后台计算时发布的进度单元类型。
Result,后台计算结果的类型。
并非所有类型都始终由异步任务使用。要将类型标记为未使用,只需使用类型 Void:
私有类 MyTask 扩展 AsyncTask { ... }
四个步骤
当一个异步任务被执行时,任务会经过4个步骤:
onPreExecute(),在任务执行后立即在 UI 线程上调用。此步骤通常用于设置任务,例如通过在用户界面中显示进度条。
doInBackground,在onPreExecute() 完成执行后立即在后台线程上调用。
此步骤用于执行可能需要很长时间的后台计算。
异步任务的参数传递到这一步。
计算的结果必须由这一步返回,并将传回最后一步。
此步骤还可以使用 publishProgress 来发布一个或多个进度单位。这些值在 UI 线程的 onProgressUpdate 步骤中发布。
onProgressUpdate,在调用 publishProgress 后在 UI 线程上调用。执行的时间是不确定的。
此方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。
例如,它可以用于动画进度条或在文本字段中显示日志。
onPostExecute,在后台计算完成后在 UI 线程上调用。后台计算的结果作为参数传递给该步骤。
取消任务
可以通过调用 cancel(boolean) 随时取消任务。调用此方法将导致对isCancelled() 的后续调用返回true。
调用此方法后,onCancelled(Object),而不是onPostExecute(Object),将在doInBackground(Object[]) 返回后调用。
为确保尽快取消任务,您应始终定期从doInBackground(Object[]) 检查isCancelled() 的返回值,如果可能的话(例如在循环内)。
线程规则
要使此类正常工作,必须遵循一些线程规则:
必须在 UI 线程上加载 AsyncTask 类。这是从android.os.Build.VERSION_CODES.JELLY_BEAN 开始自动完成的。
任务实例必须在 UI 线程上创建。
执行必须在 UI 线程上调用。
请勿致电onPreExecute(), onPostExecute, doInBackground, onProgressUpdate手动。
任务只能执行一次(如果尝试第二次执行将抛出异常。)
内存可观察性
AsyncTask 保证所有回调调用都以这样一种方式同步,即以下操作在没有显式同步的情况下是安全的。
在构造函数或onPreExecute中设置成员字段,并在doInBackground中引用。
在doInBackground中设置成员字段,在onProgressUpdate和onPostExecute中引用。
执行顺序
首次引入时,AsyncTask 是在单个后台线程上串行执行的。从android.os.Build.VERSION_CODES.DONUT 开始,这已更改为允许多个任务并行运行的线程池。
从android.os.Build.VERSION_CODES.HONEYCOMB开始,任务在单线程上执行,避免并行执行导致的常见应用错误。
如果你真的想要并行执行,你可以用THREAD_POOL_EXECUTOR.调用executeOnExecutor(java.util.concurrent.Executor, Object[])