轻松使用 AsyncTask 和 ProgressDialog
在使用 AsyncTask 和 ProgressDialog 时如何处理屏幕旋转。
引言
在本文中,我将尝试展示如何创建一个小框架,它可以帮助您开发具有异步操作和进度对话框的应用程序,而无需代码重复,并处理配置更改。
背景
为了避免应用程序在复杂任务上冻结,应该将它们的执行移到单独的线程中。正如 Android 开发人员参考资料中所提到的,使用 AsyncTask
是最好的方法。为了等待任务完成并报告当前状态,通常使用 ProgressDialog
。
在完美的世界里,它们工作得非常好,您不需要为此编写大量代码。几个代码片段就足够了。但是,当您开始更改配置(至少旋转屏幕)时,这个童话故事就结束了,因为 Android 会重新创建 activity,或者当您尝试在不同的 activity 中重复相同的功能时。
Activity 清理
所以我决定从 activity 中删除支持代码,并将其移到一个单独的类中,以便在项目中重用它。 activity 应该只创建一个特定的任务,将其传递给这个类,并提供一个回调来处理任务完成。其余的功能(显示对话框、更新进度消息、关闭对话框、调用完成处理程序)是通用的,应该在这个新类 AsyncTaskManager
中实现。
但是除了任务创建和完成处理之外,activity 还应该在配置更改的重新创建之间保留此任务。此功能也可以委托给 AsyncTaskManager
。
最后,activity 应该包含几行代码来执行以下操作
- 在 activity 创建时创建
AsyncTaskManager
- 让
AsyncTaskManager
处理保留的任务并自动运行它 - 创建新的
AsyncTask
,使用它设置AsyncTaskManager
,然后运行它 - 让
AsyncTaskManager
保留任务 - 处理任务完成
mAsyncTaskManager = new AsyncTaskManager(this, this);
mAsyncTaskManager.handleRetainedTask(getLastNonConfigurationInstance());
mAsyncTaskManager.setupTask(new Task(getResources()));
return mAsyncTaskManager.retainTask();
为了减少 AsyncTaskManager
和 activity 之间的耦合,我创建了一个接口,该接口应该由使用相同方法的任何 activity 实现。
public interface OnTaskCompleteListener {
void onTaskComplete(Task task);
}
参数中的 Task
最初被创建为一个异步任务,因此我可以获取结果或检查此任务是否被取消。
AsyncTaskManager 实现
AsyncTaskManager
现在负责 AsyncTask
和 ProgressDialog
管理,其逻辑可以实现如下
- 在启动时创建对话框
- 在任务分配时,以某种方式将任务状态(进度消息)绑定到对话框并运行任务
- 当应该保留任务时,从任务中取消绑定对话框,并在恢复时重新绑定
- 在对话框取消时取消任务
- 在任务完成后关闭对话框
- 在任务取消或完成时向 activity 报告完成情况(通过
OnTaskCompleteListener
)
为了组织这样的通信,我引入了另一个接口来将任务绑定到 AsyncTaskManager
public interface IProgressTracker {
void onProgress(String message);
void onComplete();
}
并实现它
@Override
public void onProgress(String message) {
if (!mProgressDialog.isShowing()) {
mProgressDialog.show();
}
mProgressDialog.setMessage(message);
}
@Override
public void onCancel(DialogInterface dialog) {
mAsyncTask.cancel(true);
mTaskCompleteListener.onTaskComplete(mAsyncTask);
mAsyncTask = null;
}
我的 AsyncTask
实现有一个特殊的方法来分配 IProgressTracker
实例,以便轻松地从每次配置更改时重新创建的其余代码中附加和分离任务
public void setProgressTracker(IProgressTracker progressTracker) {
mProgressTracker = progressTracker;
if (mProgressTracker != null) {
mProgressTracker.onProgress(mProgressMessage);
if (mResult != null) {
mProgressTracker.onComplete();
}
}
}
如您所见,AsyncTask
在字段中保留进度消息和操作结果,并在附加时调用特定方法。因此,如果您的任务在 activity 被销毁时已完成,则在新的 setProgressTracker
调用时,所有回调都将运行,并且 activity 将收到完成通知。
AsyncTask 实现
自定义 AsyncTask
实现非常简单明了,看起来像一个标准解决方案,除了提到的 setup 方法。除此之外,onProgressUpdate
方法应该调用 IProgressTracker.onProgress
,而 onPostExecute
方法应该调用 IProgressTracker.onComplete
。
结论
现在,任何 activity 都可以使用此解决方案。只需在其中添加五行代码,并使用示例代码中的 Task
作为您自己的任务的超类。您可以根据需要在任何方向旋转手机,但所有这些配置更改都将得到正确处理。
这种方法是在我的新应用程序 Lingo Quiz Full 和 Lingo Quiz Lite 中实现的,当它从文件导入单词或从 Google 请求翻译或设置初始词典集时。