如何在Android中执行后台操作,使用Fragments正确更新UI?

时间:2014-08-01 19:18:07

标签: java android android-asynctask android-fragmentactivity

我无法找到满足我所有要求的任何解决方案。

在我的应用程序中,我使用AsyncTasks执行一些操作,例如将数据保存到内存或从数据库中读取数据。我在onPreExecute中创建了一个进度对话框,更新了onProgressUpdate中的进度值,并在onPostExecute中关闭了对话框。

最近我切换到Fragment API(我使用支持库来定位旧版本的Android),这意味着我的活动子类FragmentActivity和对话框子类DialogFragment

切换到Fragment API引起了一个众所周知的问题 - 有时我会遇到以下异常:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

例如,当用户启动后台操作(出现进度对话框)时,会发生这种情况,使用主页按钮最小化应用程序,并在活动处于后台时完成操作。然后,应用程序尝试关闭对话框,但由于活动状态已保存,因此失败。

我理解这个问题。可以通过确保推迟对UI的更改直到恢复活动来解决此问题,如本文所述:How to handle Handler messages when activity/fragment is paused

但是,这种解决方案会导致另一个问题。如果在活动处于后台并且稍后活动被Android杀死时操作结束怎么办?当用户导航回应用程序时,它会恢复其在onSaveInstanceState中保存的状态。因此,进度对话框仍然可见,其进度值与将活动放入后台时相同。一条应该解雇它的消息从未被处理过,并且在活动被杀死时丢失了。

正确处理所有描述问题的正确解决方案是什么?如何在活动处于后台时允许更改用户界面,或者至少允许推迟用户界面更改,并确保在Android被杀死的情况下他们不会丢失?该解决方案必须允许跟踪后台任务的进度。

2 个答案:

答案 0 :(得分:2)

避免你所描述的情况的唯一确定方法是将结果保存到某种存储中。您可以启动服务来执行长时间运行的任务,并将结果写入数据库,并在完成时发送本地广播。

如果活动恰好位于前台,它将接收广播并更新其状态以了解该过程已完成,并可删除有关任务的信息 从您使用的任何持久存储机制。

如果活动在后台,则服务将完成,发送广播并保留结果。下次活动到达前台时,它应检查此持久存储并查看是否存在未解决的任务状态,并更新其状态以进行匹配。

因此,一个示例纲要可能是(让我们使用“上传照片”作为任务):

  1. 用户点击按钮开始上传图像

  2. 活动启动服务以将图像上传至远程服务

  3. 活动为您定义的某些广播事件注册LocalBroadcastManager(例如com.mypackage.ACTION_PHOTO_UPlOADED

  4. 服务会保留有关任务的一些信息(例如SharedPreferences.putBoolean(“TASK_PHOTO_UPLOADED”,false)

  5. 当服务处理上传任务时,活动显示某种加载UI
  6. 用户按下主页并将应用程序发送到停止状态

  7. 活动取消注册本地广播经理

  8. 服务完成上传图像

  9. 该服务发送一个未使用的本地广播(com.mypackage.ACTION_PHOTO_UPlOADED),因为该活动不再是在监听<
    li>
  10. 服务会更新持久信息(SharedPreferences.putBoolean("TASK_PHOTO_UPLOADED", true)

  11. Android取消活动,保存其状态

  12. 用户稍后返回活动

  13. 活动检查onResume()中的服务以查看是否存在未处理的任务结果(if (SharedPreferences.has("TASK_PHOTO_UPLOADED"))),然后检查是否应该更新状态。

    < / LI>
  14. 如果照片上传密钥在那里,并且为true,则Activity会删除对话框片段并从SharedPreferences中清除TASK_PHOTO_UPLOADED键。

    如果照片上传密钥在那里,则是false,Activity注册本地广播管理员以等待事件完成

答案 1 :(得分:-1)

  • 您的问题很长,没有任何代码示例,我试着想出最好的答案,我为您做了一个专门为您做的项目 应该在android中使用onSaveinstance状态来解决所有问题 可能存在的问题

  • 我在下面写了一篇解释文章,清除你所有的疑惑


在Android生命周期和处理Fragments

  • Activity container

  • fragments
  • oncreate的{​​{1}}

  • 安装第一个片段
  • 当我们使用片段添加替换等时,我们需要使用android Activity引用而不是fragment

  • 每次我们将片段挂载到容器时,将片段保留在classreference

  • 在项目中,我们可以观察到我们正在backstack收集小部件的所有状态并存储在局部变量中并使用此局部变量,然后将此局部变量传递给onpause()事件访问onSaveInstance()中的这些标记设置为视图对象。我们使用此过程,因为localvariables在类中保留,但视图对象在onActivityCreatd()中为null。在onSaveInstance - Activity - FragmentOne - FragmentTwo - FragmentOne - OrientationChange

  • Android OrientationChange能够保留状态static objects但必须重置onOrientation change dynamic Objects使用localvariables更改值,如上所述

  • 如果我们使用动态片段,我们在使用onOrientation恢复动态对象之前在OnActivityCreated()事件中创建动态对象

  • 该片段已添加到saveInstanceState事件的背板上

  • 如果屏幕导航为onPause - Activity - FragmentOne - FragmentTwo - FragmentOne,则按下后退按钮导航即可FragmentTwo - FragmentTwo - FragmentOne - FragmentTwo - FragmentOne,因此我们可以清楚地看到我们的路径被android backstack保持在轨道上

  • 如果路径为Activity - Activity并且第一次更改方向,则触发的事件如下 FragmentOne - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart

  • 如果路径为FragmentOne-onResume - Activity - FragmentOne并首次更改方向,则触发的事件如下:

orientationchange - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart

  • 如果路径为FragmentOne-onResume - Activity - FragmentOne - orientationchange并首次更改方向,则触发的事件如下:

orientationchange - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart

  • 如果路径为FragmentOne-onResume - Activity - FragmentOne - orientationchange - orientationchange并首次更改方向,则触发的事件为关注

FragmentTwo - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onStop - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentTwo-onActivityCreated - FragmentOne-onStart

  • 如果路径为FragmentOne-onResume - Activity - FragmentOne - orientationchange - orientationchange - FragmentTwo并首次更改方向然后发起的事件如下

orientationchange - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentOne-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onStop - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentTwo-onActivityCreated - FragmentOne-onStart - FragmentOne-onResume - FragmentOne-onPause - FragmentOne-onSaveInstanceState - FragmentOne-onSaveInstanceState - FragmentOne-onStop - FragmentOne-onDestroy - FragmentOne-onDetach - FragmentOne-onDestroy - FragmentOne-onDetach - MainActivity-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onAttach - FragmentOne-onCreate - FragmentOne-onCreateView - FragmentTwo-onActivityCreated - FragmentOne-onStart


<强>综述 ::

  • 现在请记住FragmentOne-onResume事件总是在关闭片段存储之前触发您要保留的值onPause,当onOrientation到来时,任何其他场景

  • 将执行下一个phonecall,因此请使用这些局部变量在此设置onSaveInstanceState

  • 中的数据
  • 接下来,活动将被推送到bundle点击主页按钮时不会丢失数据

  • 所以当backstackonActivityCreated次见证时获取数据时

  • 还记得android在销毁片段时总是完成bundle' and store it back to your,如果它被发送到lifecycle片段不会被销毁(当你按下主页按钮时)android只在需要时才会销毁来自backstack的更多空间会自动发生


如果您需要更多信息,请与我们联系