【问题标题】:Using the Android Application class to persist data使用 Android Application 类来持久化数据
【发布时间】:2011-05-11 16:02:06
【问题描述】:

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

【问题讨论】:

  • 请记住,如果您的应用程序进入后台,您的应用程序中的数据仍然可以被删除,因此这不是您始终希望能够取回的持久数据的解决方案。它只是作为一种不必经常重新创建昂贵对象的方法。
  • 梅拉;我不认为该应用程序“通常”被删除(尽管有人在此线程后面指出,它“可以”被删除)。我可能会采用某种类型的“混合”方法来使用应用程序存储和加载数据,然后在清单文件中的活动上使用“android:orientation”属性来覆盖的正常行为拆除和重建活动。当然,所有这些都假设应用程序可以确定“何时”销毁它,以便可以持久保存数据。

标签: android application-lifecycle


【解决方案1】:

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

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

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

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.

我在“全局单例”部分讨论它here in my blog post

【讨论】:

  • 很遗憾,该地址不再提供相关博客文章。
  • 我一直在我的网站上移动东西。在修复之前,您可以在 archive.org 上找到它:web.archive.org/web/20130818035631/http://www.bryandenny.com/…
  • 我知道这是一篇旧帖子,但我只是遇到了一个可以解决的问题,但是这个类需要以某种方式在清单中声明,不是吗?我无法上课,所以觉得这就是我所缺少的......
  • @ZivKesten 如何将 name= 属性添加到清单中的应用程序标签?
  • @mgc 谢谢你已经有一段时间了,是的,这就是我最终解决它的方式,而且我在需要的地方创建了该类的实例,方法是给它一个带有强制转换的 getApplicationContext()类
【解决方案2】:

那些指望Application 实例的人是错误的。起初,似乎Application 存在只要整个应用程序进程存在,但这是一个错误的假设。

操作系统可能会根据需要终止进程。所有进程分为5个级别的“可杀性”specified in the doc

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

我认为更好的方法是persist your data to internal storage file,然后在您的活动恢复时阅读它。

更新:

我收到了很多负面反馈,所以是时候添加说明了。 :) 好吧,最初我确实使用了一个错误的假设,即状态对应用程序非常重要。但是,如果您的应用正常,有时状态会丢失(可能是一些图像将被重新读取/重新下载),那么将其保留为 Application 的成员是完全可以的。

【讨论】:

  • 如果应用程序被杀死,那么谁在乎,对吧?应用程序不见了。据我了解,Android 将回收包含诸如活动之类的内存的进程。如果包含应用程序的进程被杀死(如果 Android 甚至会这样做?),那本质上就像杀死应用程序一样。用户将需要再次启动应用程序,此时,谁在乎呢?这是应用程序的一个新实例。
  • 这对我们的生产来说是一个不愉快的惊喜。相信我,Android 会杀死进程,它仅取决于 RAM 状态和文档中描述的其他因素。这对我们来说是一场噩梦,所以我只是分享我的真实经历。好吧,我们在模拟器上没有这个,但在现实世界中,一些设备的应用程序“超载”,因此终止后台进程是正常情况。是的,如果用户随后决定将应用程序置于前台 - 操作系统会恢复其堆栈,包括 Application 实例,但是除非您将其持久化,否则不会有您依赖的静态数据。
  • 我想我可能会使用混合方法。我已经知道了覆盖方向变化的清单技巧(这有其他好处)。由于应用程序是一个游戏,我不确定在启动之间保存数据是否足够“重要”;尽管它可能不会很难,因为大多数数据都可以序列化(尽管我不想在每次方向更改之间进行序列化和反序列化)。我非常感谢您的意见。我不会说依赖 App 实例的那些是“错误的”。很大程度上取决于应用程序:)。
  • @Arhimed 您过于概括您的答案。并根据您的假设提出一种狭窄的方法。错误假设:静态变量中保存的数据需要在应用程序的会话中持久化。可能有许多用例,其中数据是微不足道的,不需要立即持久化。
  • 我有大约 1mb 结构复杂的数据。当设备超负荷工作时,序列化/反序列化可能会花费我 2-3 秒。在活动之间保存/加载的想法花费了太多时间。我使用应用程序作为存储。当然,我存储在应用程序实例中的数据类会检查每个方法 - 数据是否仍然存在或必须加载。所以 Dave 必须: 1. 提供加载/保存功能 2. 在应用程序中保存数据。 3. 访问数据的三重校验逻辑。
【解决方案3】:

如果您想在活动之外访问“全局单例”并且不想通过所有涉及的对象传递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();
}

但在传递对avoid memory leaks 的上下文引用时要非常小心。

【讨论】:

  • 您忘了注意,您必须在清单中添加 android:name=".ApplicationController" xml 属性的应用程序标签才能实例化类。
  • 您实际上不需要扩展 Application 来执行此操作。您可以在任何类中声明一个静态成员变量来执行此操作。
【解决方案4】:

戴夫,这是什么数据?如果是与整个应用程序相关的一般数据(例如:用户数据),则扩展 Application 类并将其存储在那里。如果数据与 Activity 相关,则应使用 onSaveInstanceState 和 onRestoreInstanceState 处理程序将数据保留在屏幕旋转上。

【讨论】:

  • 如果数据真的很大,要存储在 Parcel 中怎么办?这就是我得到的:android.os.TransactionTooLargeException: data parcel size 838396 bytes
【解决方案5】:

您实际上可以覆盖方向功能,以确保您的活动不会被破坏和重新创建。看here

【讨论】:

  • 你可以做很多事情。这并不意味着它们是好主意。这不是一个好主意。
  • 通过更改屏幕方向进行测试是确保您的应用执行 Android 假设的最简单方法。
【解决方案6】:

您可以创建应用程序类并将所有数据保存在该类中,以便在应用程序的任何位置使用。

【讨论】:

    【解决方案7】:

    我知道这是一个非常古老的问题,但使用 ViewModel from the jetpack components 是在 Activity 轮换之间保存数据的最佳方式。

    ViewModel 类旨在以生命周期意识的方式存储和管理与 UI 相关的数据。 ViewModel 类允许数据在屏幕旋转等配置更改中保留下来。

    【讨论】:

      猜你喜欢
      • 2012-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多