如何在 Android 上安排长时间(耗时)的操作?
Posted
技术标签:
【中文标题】如何在 Android 上安排长时间(耗时)的操作?【英文标题】:How to arrange long (time consuming) actions on Android? 【发布时间】:2011-01-15 12:15:58 【问题描述】:例如,我们在 SomeActivity 中,该活动有一个按钮,用于调用将文件从一个目录移动到另一个目录(我们称之为作业)。
在黑莓上我会:
-
推送一个不可取消的弹出窗口(对话屏幕)说“请稍候...”
启动一个完成任务的线程
在线程完成时关闭弹出窗口
这种方法 99.99% 可以保证我们在任务结束后保持在同一个屏幕上,用户只是看到弹出窗口并等待任务完成。设备轮换或任何不会破坏所需工作流程的方式。
在 android 上,情况发生了变化。我知道可能会提供 AsyncTask 来解决我的问题。甚至还有一个很好的example 应该如何使用它。但由于无法保证 Activity 实例将存活多长时间,因此应在 onSaveInstanceState 上取消 AsyncTask(并在 onRestoreInstanceState 上重新启动)。这意味着使用 AsyncTask 并不能保证我们一旦开始就能够完全完成工作。在某些情况下,作为发送创建用户的 http 发布请求,我不想在重新运行 AsyncTask 时遇到“用户已存在此登录”的麻烦。这是可能的,因为 AsyncTask 可以在请求已经发送时被中断(并且服务器实际上正在做它的工作 - 创建一个新用户),但是 AsyncTask 在我们得到响应之前被取消。
在 Android 上是否有任何解决方案来获得上述类似 BB 的行为?
【问题讨论】:
【参考方案1】:但由于无法保证如何 一个 Activity 实例会存在多久 AsyncTask 应该在 onSaveInstanceState (并重新启动 onRestoreInstanceState)。
或者让它由Service
管理。
【讨论】:
我应该研究这个组件,因为已经有人建议我使用它两次。 嗨,CommonsWare。在您的任何书籍中,是否详细解释了应如何在 Android 上对长期运行的作业进行架构/编码? 这在一定程度上取决于您将什么定义为“长时间运行的作业”。我在一本书(commonsware.com/Android)中介绍了使用 AsyncTask 的服务——请参阅github.com/commonsguy/cw-android/tree/master/Service/… 了解相关项目。我在另一本书 (commonsware.com/AdvAndroid) 中介绍了使用 AlarmManager 来避免永久服务 - 请参阅 github.com/commonsguy/cw-advandroid/tree/master/SystemServices/… 了解该项目。 现在才看到你的回复(我以为会有关于新评论的某种电子邮件通知,但没有)。 我正在寻找一种解决方案,用于在进度弹出窗口下正确处理长时间运行的作业线程,假设用户从 Activity 调用它。问题是如何将作业线程与 Activity 的生命周期“同步”。那是我原来的帖子。【参考方案2】:如果您的 Activity 想要停留在屏幕上,您可以像这样简单地启动一个线程:
final File fromFile = ...;
final File toFile = ...;
new Thread()
@Override
public void run()
// do something with fromFile, toFile
.start();
这样,GUI线程就可以做其他的事情了,比如显示一个
android.app.ProgressDialog
另外,考虑使用
使对话框不可取消 ProgressDialog.setCancelable(false);
这样用户只能通过 HOME-Key 离开,您会在何时收到通知
Activity.onPause()
被调用。此外,您可能想要查看 Wakelocks,以阻止屏幕变黑,并将您的应用程序推到可能被杀死的后台。你会在线程中这样做:
PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
wakeLock.acquire();
// ... copy stuff ...
wakeLock.release();
当然,当用户通过 HOME 键离开时,您也必须释放唤醒锁。
最后,如果您想从后台线程调用 GUI-Elements,这仅在线程是 GUI-Event-Loop 的一部分时才有效,就像您正在运行的正常线程一样,当被调用时...-方法。为了实现这一点,您的后台线程必须通过处理程序回调到 GUI 线程。像这样:
private Handler mHandler = new Handler()
@Override
public void handleMessage(Message msg)
Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
// ... do GUI actions ...
;
// ... in Thread ...
int lvInfo = 77;
mHandler.sendEmptyMessage(lvInfo);
你甚至可以像这样在消息中放置对象:
Message txtMsg = Message.obtain();
textMsg.obj = "Hello World";
mHandler.sendMessage(lvTextMsg);
【讨论】:
rflexor,感谢您的回答。专门用于唤醒锁点。【参考方案3】:2010 年 5 月,Google 发布了一个名为 Developing Android REST client applications 的新 IO 会话,它解释了如何实现我所要求的。
原来这个问题相当复杂,所以没有简单快捷的解决方案。该解决方案需要深入了解 Android 平台/API。这是应用程序流程/活动生命周期的灵活性造成的代价。
我觉得有些奇怪,为什么在 Android 的第一个版本中没有提供此信息。看起来 Google 知道如何编写 100% 无错误的应用程序,但出于某种营销原因并没有分享这种方法。试想一下,到 2010 年 5 月,有多少错误的应用程序被编写出来。
无论如何,我很高兴我现在有了我们称之为最佳实践方法的东西。
【讨论】:
以上是关于如何在 Android 上安排长时间(耗时)的操作?的主要内容,如果未能解决你的问题,请参考以下文章