Android 应用程序恢复时保存列表数据的状态
这是我的设置 我有一个主要的Android 应用程序恢复时保存列表数据的状态,android,android-activity,android-listview,android-fragments,Android,Android Activity,Android Listview,Android Fragments,这是我的设置 我有一个主要的SherlockFragmentActivity。它将许多列表片段与片段事务来回交换。要指示加载,只要ListFragment加载我调用的数据: setSupportProgressBarIndeterminateVisibility(true); 问题是: 当上面提到的主活动首次启动时,或者用户离开并转到其他应用程序,然后在一段时间后重新启动此应用程序时,SherlockFragmentActivity似乎会重新加载,操作栏中没有进度对话框,屏幕会在几秒钟内保持白
SherlockFragmentActivity
。它将许多列表片段
与片段事务
来回交换。要指示加载,只要ListFragment
加载我调用的数据:
setSupportProgressBarIndeterminateVisibility(true);
问题是:
当上面提到的主活动
首次启动时,或者用户离开并转到其他应用程序,然后在一段时间后重新启动此应用程序时,SherlockFragmentActivity
似乎会重新加载,操作栏中没有进度对话框
,屏幕会在几秒钟内保持白色,然后列表数据修复(长度取决于数据连接)
下面是一些补充代码:当主/base活动第一次加载时,这是我在onCreate()中首先做的事情之一:
followFragment
是将始终在此实例中加载的片段。它包含一个ListView
和一个AsyncTask
从MySQL
数据库中提取数据
我的问题:如何防止这种延迟?当用户长时间离开时,如何维护数据 根据,在调用setSupportProgressBarInDeterminateVibility()之前,必须请求进度条功能。
:
另一个问题是重新加载片段,这是由于Android杀死了您的ListFragment
,因此必须重新加载这些片段可以通过覆盖onSaveInstanceState(Bundle outState)
并在那里缓存要在ListFragment
中检索的数据来解决:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(savedInstanceState != null) {
// retrieve data from Bundle here
} else {
// no data, we need to reload from network
}
// initialize your View here
}
但是,这个方法不能保证一直运行(它不在片段生命周期中)。因此,您还应该确保将数据缓存在onPause()
中,并使用它,而不是总是从网络连接加载数据
@Override
public void onPause() {
super.onPause();
SharedPreferences prefs = getActivity().getSharedPreferences();
SharedPreferences.Editor editor = prefs.edit();
// put your data here using editor
editor.commit();
}
然后,您可以通过检索SharedReferences
的实例,并使用prefs.getString(字符串键)
和其他方法,将此数据加载到onCreateView()
中。这是正常的行为,因为当您的应用程序处于后台时,您的活动已被终止,以便为其他应用程序节省内存。当它回到前台时,系统会重新创建你的活动,这将重新创建你的片段
但如果您确实希望避免重新创建片段,可以在片段的onCreate方法中使用setRetainInstance:
公共void setRetainInstance(布尔保留)
控制是否在活动重新创建期间保留片段实例(例如从配置更改)。这只能用于不在后堆栈中的片段。如果设置,则重新创建活动时片段生命周期将略有不同:
不会调用onDestroy()(但仍然会调用onDetach(),因为片段正在从其当前活动中分离)。
由于未重新创建片段,因此不会调用onCreate(Bundle)。
仍将调用onAttach(活动)和onActivityCreated(捆绑)
并在FragmentActivity的onActivityCreated方法中使用如下内容:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
// Check to see if we have retained the worker fragment.
mRetainableFragment = (RetainedFragment)fm.findFragmentByTag("fragmentTag");
// If not retained (or first time running), we need to create it.
if (mRetainableFragment == null) {
mRetainableFragment = new RetainedFragment();
// Tell it who it is working with.
mRetainableFragment.setTargetFragment(this, 0);
fm.beginTransaction().add(mRetainableFragment, "fragmentTag").commit();
}
}
但请注意,这应该只用于无头片段(没有UI的片段,即onCreateView中返回null,也称为工作片段)。不过,您仍然可以对UI片段使用此方法,但google不建议使用此方法,在这种情况下,数据必须存储为活动中的成员(字段)。如果Bundle类支持应存储的数据,则可以使用onSaveInstanceState()方法将数据放置在Bundle中,并使用onActivityCreated()方法检索该数据
此外,这仅在片段未添加到backbackback时有效。当您在延长时间后返回活动时,整个应用程序将重新启动。因此,您不能依赖对象变量来保存数据
所以,在activity onStop()方法中将数据保存到某些本地存储中,可以避免前面提到的延迟。例如,共享首选项
当您调用onCreate()时,请检查是否保存了数据,并在数据存在时使用它(并在下次清理时启动“清理”),否则启动asynctask 当您的应用程序被终止时,您将丢失活动状态和数据!关于您的异步任务
,我可以假设两种情况:
1.您正在从Web服务器
中提取一些数据。在这种情况下,我个人认为缓存从webserver
检索的数据比实现serializable
更好
2.您正在从本地数据库中提取大量数据(这导致检索数据需要一些时间)。在这种情况下,我建议只检索您需要的数据,而不是更多!(例如,您可以检索20个项目,当用户滚动到ListView
的末尾时,可以检索下20个项目)。
此解决方案可帮助应用程序更快地检索数据
PS:为了给您一个如何使用缓存功能实现WebserviceModule
的线索,我假设它位于AsyncTask
中,您可以将webserver
的每个响应保存在SD卡中,并且每次尝试从webserver
检索某些资源时,您应该检查SD卡,查看您的请求是否已发送和缓存!对于每个请求,您应该基于url
和post参数创建一个唯一的签名,以识别缓存文件。是,这是一个UI片段。所以我想我需要使用onSaveInstanceState()
方法。您将如何使用它并保存列表数据?列表由一个列表组成。我通常将数据存储在一个管理器(单例)中,在那里我可以从任何地方获取数据。这样我就不需要保存UI实例状态。否则,您可以轻松地存储列表,因为它实现了serializ
@Override
public void onPause() {
super.onPause();
SharedPreferences prefs = getActivity().getSharedPreferences();
SharedPreferences.Editor editor = prefs.edit();
// put your data here using editor
editor.commit();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
// Check to see if we have retained the worker fragment.
mRetainableFragment = (RetainedFragment)fm.findFragmentByTag("fragmentTag");
// If not retained (or first time running), we need to create it.
if (mRetainableFragment == null) {
mRetainableFragment = new RetainedFragment();
// Tell it who it is working with.
mRetainableFragment.setTargetFragment(this, 0);
fm.beginTransaction().add(mRetainableFragment, "fragmentTag").commit();
}
}