使用Android应用程序类持久化数据


112

我正在开发一个相当复杂的Android应用程序,该应用程序需要有关该应用程序的大量数据(我说总共约500KB -对于移动设备来说这算大吗?)。据我所知,应用程序中的任何方向更改(更确切地说是在活动中)都会导致活动的完全破坏和重新创建。根据我的发现,Application类没有相同的生命周期(即,出于所有意图和目的,总是被实例化)。将状态信息存储在应用程序类中,然后从Activity中引用它是否有意义,或者由于移动设备上的内存限制,通常这不是“可接受的”方法吗?我真的很感谢有关此主题的任何建议。谢谢!


8
请记住,如果您的应用程序进入后台,仍然可以删除应用程序中的数据,因此,这并不是解决您一直希望能够取回的持久数据的解决方案。它只是一种不必经常重新创建昂贵对象的方法。
谢丽尔·西蒙

2
Mayra; 我不认为该应用程序“通常”被删除了(不过,正如稍后在该线程中指出的那样,它“可以”被删除)。我可能会采用某种“混合”方法,即使用应用程序存储和加载数据,然后在清单文件中的活动上使用“ android:orientation”属性来覆盖拆除并重建活动。当然,所有这些假设都假定应用程序可以确定“何时”销毁它,以便可以保留数据。
戴夫

Answers:


134

我认为500kb不会有什么大不了的。

您所描述的正是我如何解决活动中丢失数据的问题。我在Application类中创建了一个全局单例,并且能够从我使用的活动中访问它。

如果将要使用很多数据,则可以在Global Singleton中传递数据。

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.

我将在我的博客文章 “ Global Singleton”下讨论此问题


1
不幸的是,相关博客文章不再在该地址提供。
mikebabcock 2014年

1
我一直在移动网站上的内容。在修复之前,您可以在archive.org上找到它:web.archive.org/web/20130818035631/http
Bryan Denny

1
我知道这是一个老帖子,但我遇到一个可能解决的问题,但是该类需要以某种方式在清单中取消,不是吗?我无法上课,所以感觉这就是我所缺少的...
Ziv Kesten 2014年

1
@ZivKesten如何在清单中的应用程序标签中添加name =属性?
MikeC 2014年

@mgc谢谢您,已经有一段时间了,是的,这就是我最终解决的方法,我还通过在其需要的地方通过将getApplicationContext()强制转换为此类来创建该类的实例
Ziv Kesten

57

那些依靠Application实例的人是错误的。首先,似乎Application整个应用程序存在的时间就一直存在,但这是一个错误的假设。

操作系统可能会根据需要终止进程。所有过程分为doc中指定的 5级“可杀伤性” 。

因此,例如,如果您的应用由于用户接听来电而进入后台,则根据RAM的状态,操作系统可能(也可能不会)杀死您的进程(破坏进程中的Application实例) 。

我认为一种更好的方法是将数据持久保存到内部存储文件中,然后在活动恢复时读取它。

更新:

我收到了很多负面反馈,因此现在该进行澄清了。:)好吧,最初我确实使用了错误的假设,认为状态对于应用程序确实很重要。但是,如果您的应用程序正常,有时状态会丢失(可能是一些图像会被重新读取/重新下载),那么将其保留为完全可以Application


14
如果应用程序被杀死,那么谁在乎呢?该应用程序不见了。据我了解,Android将回收包含“活动”之类的内存的进程。如果包含应用程序的进程被杀死(如果Android能够做到这一点?),这本质上就像是杀死该应用程序。用户将需要再次启动该应用程序,此时,谁在乎?这是应用程序的新实例。
安德鲁(Andrew)2010年

14
对于我们的生产而言,这是令人不快的惊喜。相信我,Android会杀死进程,它仅取决于RAM状态和文档中描述的其他因素。这对我们来说是一场噩梦,所以我只分享我的真实经验。好吧,我们在仿真器上没有这个功能,但是在现实世界中,某些设备已被应用程序“重载”,因此杀死后台进程是正常情况。是的,如果用户随后决定将应用程序置于前台-操作系统将还原其堆栈(包括Application实例),但是除非您坚持使用,否则不会依赖您的静态数据。
Vit Khudenko

2
我想我可能会使用混合方法。我已经知道了覆盖方向变化的清单技巧(还有其他好处)。由于该应用程序是游戏,因此我不确定在两次启动之间持久保存数据是否足够“重要”。尽管由于大多数数据都可以序列化,所以这可能不会很困难(尽管我不想在每次方向更改之间进行序列化和反序列化)。我绝对感谢您的投入。我不会说那些依赖于App实例的人是“错误的”。在很大程度上取决于应用程序:)。
戴夫

1
@Arhimed,您过于笼统地回答了。并根据您的假设建议一种狭窄的方法。错误假设:静态变量中保存的数据需要在应用程序的各个会话之间持久保存。在许多用例中,数据是微不足道的,不需要立即保存。
Mandar Limaye 2012年

2
我有大约1mb的数据,结构复杂。当设备超负荷工作时,序列化/反序列化可能要花费我2-3秒的时间。在两次活动之间保存/加载的想法花费了太多时间。我使用应用程序作为存储。当然,我存储在应用程序实例中的数据类在每个方法上都有检查-数据是否仍然存在或必须加载。因此Dave必须:1.提供加载/保存功能2.在应用程序中保留数据。3.用于检查数据的三重检查逻辑。
Kostadin

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
您忘记了要为实例化该类,必须在清单中添加android:name =“。ApplicationController” xml属性application标记。
eggie5 2012年

您实际上不需要扩展Application即可执行此操作。您可以在任何类中声明一个静态成员变量来执行此操作。
David Wasser

2

戴夫,这是什么样的数据?如果是与整个应用程序有关的常规数据(例如:用户数据),则扩展Application类并将其存储在该类中。如果数据与活动有关,则应使用onSaveInstanceState和onRestoreInstanceState处理程序将数据持久保存在屏幕旋转中。


如果数据真的很大要存储在包裹中怎么办?这就是即时消息:android.os.TransactionTooLargeException:数据包大小838396字节
Arjun Issar



0

我知道这是一个非常老的问题,但是使用jetpack组件中ViewModel是在Activity轮换之间保留数据的最佳方法。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.