使用Android Application类持久化数据

113

我正在开发一款相当复杂的Android应用程序,需要获取大量与该应用程序相关的数据(我认为总共约500KB - 这对移动设备来说算大吗?)。据我所知,在应用程序中的任何方向更改(在活动中更精确)都会导致完全销毁和重建该活动。根据我的调查结果,Application类没有相同的生命周期(即它在所有情况下都被实例化)。把状态信息存储在应用程序类中,然后从活动中引用它是否有意义,或者由于移动设备上的内存限制而通常不是“可接受”的方法? 我真的很感激关于这个主题的任何建议。谢谢!


9
请记住,如果您的应用程序进入后台,应用程序中的数据仍然可能会被删除,因此这并不是保留始终需要检索的数据的解决方案。它只是一种不必经常重新创建昂贵对象的方法。 - Cheryl Simon
2
Mayra;我不认为应用程序通常会被删除(尽管正如本帖后面有人指出的那样,它“可以”被删除)。我可能会采用某种“混合”方法,使用应用程序来存储和加载数据,但然后在清单文件中的活动上使用“android:orientation”属性来覆盖拆除和重建活动的正常行为。当然,所有这些都假定应用程序可以确定“何时”被销毁,以便数据可以持久化。 - Dave
7个回答

133

我认为500kb不会是一个大问题。

你描述的正是我解决在活动中数据丢失问题的方法。我在应用程序类中创建了一个全局单例,并能够从我使用的活动中访问它。

如果要经常使用数据,可以在全局单例中传递数据。

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

然后在任何活动中通过以下方式调用它:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

我在我的博客文章中这里讨论了它,在“全局单例”部分下。


1
很遗憾,相关的博客文章在该地址上已不再可用。 - mikebabcock
1
我一直在调整我的网站。在它修复之前,您可以在archive.org上找到它,链接如下:https://web.archive.org/web/20130818035631/http://www.bryandenny.com/index.php/2010/05/25/what-i-learned-from-writing-my-first-android-application - Bryan Denny
1
我知道这是一个旧帖子,但我刚遇到了一个可能可以解决的问题,然而这个类需要在清单中声明,对吗?我无法访问这个类,所以感觉这就是我缺失的东西... - Ziv Kesten
1
@ZivKesten,在清单文件中的应用程序标签内添加name属性怎么样? - MikeC
Application对象可能会被销毁,除非getter方法重新创建单例,否则如果你运气不好,就会出现空引用错误。http://www.developerphil.com/dont-store-data-in-the-application-object/ - Jonatan
显示剩余3条评论

58
那些依赖于Application实例的人是错误的。一开始,似乎Application存在的时间和整个应用程序进程的存在时间一样长,但这是错误的假设。
操作系统可能会根据需要终止进程。所有进程分为5个“可终止性”级别,在文档中指定
因此,例如,如果您的应用程序由于用户回答来电而转入后台,则根据RAM的状态,操作系统可能(或可能不会)终止您的进程(在该过程中销毁Application实例)。
我认为一个更好的方法是将您的数据持久化到内部存储文件,然后在您的活动恢复时读取它。
更新:
我收到了很多负面反馈,所以现在是时候澄清一下了。 :) 好吧,最初我确实做出了一个错误的假设,即状态对于应用程序确实很重要。但是,如果您的应用程序没有问题,即有时状态会丢失(可能是某些图像将被重新读取/重新下载),那么将其保留为Application的成员就完全没问题了。

15
如果应用程序被关闭,那又有谁会在意呢?应用程序已经消失了。据我所知,Android将回收包含活动(Activity)等内存的进程。如果包含应用程序的进程被杀死(如果Android会这样做的话?),那就基本上相当于杀死了该应用。用户需要再次启动该应用程序,此时谁在乎呢?这是一个新的应用程序实例。 - Andrew
16
这对我们的生产来说是个不愉快的惊喜。相信我,安卓会杀死进程,这取决于RAM状态和文档中描述的其他因素。这对我们来说是一场噩梦,所以我只是分享我的真实经验。好吧,在模拟器上我们没有遇到这个问题,但在现实世界中,一些设备被应用程序“超载”,因此杀死后台进程是一种正常情况。是的,如果用户随后决定将应用程序提升到前台-操作系统会恢复其堆栈,包括Application实例,但是除非您进行了持久化,否则不会保留您所依赖的静态数据。 - Vit Khudenko
2
我认为我可能会采用混合方法。我已经知道了覆盖方向更改的清单技巧(这还有其他好处)。由于应用程序是游戏,我不确定在启动之间持久化数据是否足够“重要”;尽管大多数数据可以序列化(尽管我不想在每次方向更改之间进行序列化和反序列化)。我非常感谢您的意见。我不会说那些依赖于App实例的人是“错误”的。很多取决于应用程序 :)。 - Dave
1
@Arhimed,您的回答过于概括了。并且基于您的假设提出了狭隘的方法。 错误的假设:静态变量中保存的数据需要在应用程序的会话之间持久化。可能有许多用例,其中数据是微不足道的,不需要立即持久化。 - Mandar Limaye
2
我有大约1MB大小、结构复杂的数据。当设备负载过重时,序列化/反序列化可能需要2-3秒钟时间。在活动之间保存/加载的想法需要太多时间。我使用应用程序作为存储。当然,我的数据类存储在应用程序实例中,并在每个方法上都有检查 - 数据是否仍然存在或必须被加载。因此,Dave必须:1.提供加载/保存函数;2.将数据存储在应用程序中;3.三重检查访问数据的逻辑。 - Kostadin
1
这是对不同问题的正确答案。如果您只为应用程序会话持久化数据,则在单例或应用程序类中使用对象进行持久化是100%正确的。如果仅用于会话信息,则始终应首选在内存中持久化,而不是磁盘上持久化。持久化到磁盘不仅速度较慢,而且会更快地磨损用户的硬件。 - CodyEngel

6
如果您想要在活动外部访问“全局单例”,并且不希望通过所有相关对象传递“Context”以获取单例,则可以在应用程序类中定义一个静态属性,该属性保存对其自身的引用。只需在“onCreate()”方法中初始化该属性即可。
例如:
public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

由于Application的子类也可以获取资源,因此您可以在定义返回它们的静态方法时轻松访问它们,例如:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

但是在传递Context引用时,请非常小心,以避免内存泄漏


6
你忘了注意,在你的manifest文件中的application标签上必须添加android:name=".ApplicationController"这个xml属性,才能实例化该类。 - eggie5
你实际上不需要扩展Application来做到这一点。你可以在任何类中声明一个静态成员变量来实现这个功能。 - David Wasser

2

Dave,这是什么类型的数据?如果这是与整个应用程序相关的通用数据(例如:用户数据),那么请扩展Application类并将其存储在那里。如果该数据涉及到Activity,则应使用onSaveInstanceState和onRestoreInstanceState处理程序来在屏幕旋转时保持数据。


如果数据太大,无法存储在包裹中怎么办? 这是我得到的错误:android.os.TransactionTooLargeException: data parcel size 838396 bytes。 - Arjun Issar

1

你实际上可以重写方向功能,以确保你的活动不被销毁和重新创建。请点击这里


18
你可以做很多事情,但这并不意味着它们都是好主意。这不是一个好主意。 - Andrew
通过更改屏幕方向进行测试是确保您的应用程序执行Android所假定的操作的最简单方法。 - 18446744073709551615

0

我知道这是一个非常老的问题,但使用Jetpack组件中的ViewModel是保留Activity旋转期间数据的最佳方式。

ViewModel类旨在以生命周期感知的方式存储和管理与UI相关的数据。ViewModel类允许数据在配置更改(如屏幕旋转)时保持不变。


0
你可以创建一个Application类,并将所有数据保存在该类中,以便在应用程序的任何地方使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接