【问题标题】:Android : Static variable null on low memoryAndroid:内存不足的静态变量null
【发布时间】:2011-06-15 09:27:42
【问题描述】:

我有一个包含一些静态变量的应用程序。 这些变量存储在一个名为 DataContext 的独立类中。 这些变量在应用程序启动时从原始文件初始化(在扩展 Application 的 MyApplication 的 onCreate() 中调用了一个名为 DataContext.initConstant() 的方法)。

(编辑:initConstant 方法使用 AsyncTask 从文件中加载此数据)。

当我的应用程序进入后台一段时间或当我的应用程序使用大量内存时,这些静态变量变为空。

  1. 如何预防?

  2. 如果不是,我应该如何处理我的静态变量?

    我有其他数据存储在静态变量中以供不同活动使用,但我在 MyApplication 的 onLowMemory() 中清除它们或将它们传递给 null。

  3. 如果这些数据太大而无法在 Intent 中序列化、无法使用数据库(无论出于何种原因)并且无法通过也可以序列化?

【问题讨论】:

  • 你能详细说明为什么数据库或序列化文件不能工作吗?
  • 我有很多信息,我现在正在改变我访问它的方式,因为我的时间很短,我们只是找出问题所在。
  • @MathieuC :请分享解决方案,我也面临同样的问题很长时间了。

标签: android memory static low-memory


【解决方案1】:

我认为这是数据缓存问题。

当用户经常交换应用程序时,不能保证在静态类中存储数据。 Android 系统会在内存不足时回收所有后台活动。静态类肯定属于这一类。

正确的做法是使用sharedPreference来持久化缓存数据。

您可以创建自己的 getter 和 setter 来获取所需的数据,并将其包装在 sharedPreference 对象周围。使用 getter 访问时,应始终检查该值是否为空或过期。使用 setter 时可以存储update_time

对于活动特定的数据,你可以使用getPreference(permission),如果你想在活动和其他应用程序组件之间共享数据,你可以使用getSharedPreference(name, permission)

通常,权限为 MODE_PRIVATE,这样数据只能在您的应用程序中访问。

您应该将数据分组并存储在不同的 sharedPreference 对象中。这是一种很好的做法,因为当您想要使该组数据无效时,只需一个班轮即可。

editor.clear(); editor.commit()

如果你想缓存复杂的对象,你应该序列化它。我更喜欢 JSON 格式。所以你需要一些转换机制。为此,我将创建扩展 JSONable 类的数据对象类。 JSONable 类将具有toJSON() 方法和readFromJSON()。这在恢复和序列化数据时很方便。

【讨论】:

    【解决方案2】:

    在您的onResume() 方法中,您可以查询静态数据以查看它是否存在,如果不存在,请重新加载。

    【讨论】:

      【解决方案3】:

      您可以使用共享首选项来存储值,而不是使用静态变量。

      注意:对于共享偏好,您也不应该给予沉重的负担。

      我已经通过使用带有 getter 和 setter 函数的超类来存储和检索共享首选项变量来解决这个问题。

      我的应用程序中的所有类都扩展了超类而不是活动。

      【讨论】:

        【解决方案4】:

        如果您不使用原始文件,我建议在加载类时进行初始化。

        例如,

        public static Map<?,?> myStaticMap = new HashMap<?,?>();
        static { //fill myStaticMap }
        

        如果您以这种方式加载文件,您确实需要担心一些更大的问题。例如,I/O 错误或延迟问题呢?您将在姜饼(如果您启用它们)中收到警告,以便在您的主线程中执行 I/O。也许您应该有一个对象来检索这些值,而不是一个具有静态字段的类。 (也许使用静态缓存,尽管您应该在检查/更改之前对其进行同步)

        【讨论】:

        • 别担心我的加载不在主线程中(我使用 AsyncTask 在我的 initConstant 方法中完成工作。
        • 如果在 AsyncTask 中调用 DataContext.initConstant(),那么当您的应用程序被系统销毁并重新启动时,在您的 Activity 被创建并期望 DataContext 被填充和实际填充的时间。这可能是您发现它为空的原因 - 它尚未重新创建,但您的一些活动希望它在运行时完全初始化。
        【解决方案5】:

        我在我的静态作用域中存储了一个User 对象和一个Client 对象。我不时注意到引用变为空。所以现在在我的吸气剂中,我检查这个值是否为空,如果是,我重新启动应用程序。

        Intent i = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
                        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        context.startActivity(i);
        

        我也可以选择重新加载客户端,因为我将访问令牌存储在 prefs 中,但是我做了很多初始化,所以我决定重新启动应用程序是最好的主意。

        【讨论】:

        • 谢谢,但这意味着如果用户的设备非常旧,应用程序可能会经常重启,不是吗?
        • 嗯,不完全是。我实际上将静态变量放在了我的 android 应用程序的 Application 类中。除非整个应用程序被删除,否则这些变量几乎永远不会变为 null。我注意到这些变为空的唯一一次是有人使用任务杀手停止应用程序但当前活动仍然存在。所以这就是为什么我认为这是一个非常罕见的情况,我会重新启动应用程序。
        【解决方案6】:

        问题很可能是您的应用程序在后台被杀死,然后在您返回时重新创建。查看Activity Lifecycle 文档,了解单个活动何时可能发生这种情况。您需要确保在正确的时间点将内存中存储的任何内容移动到更永久的存储空间,以避免在应用程序被终止时丢失该信息。

        我不确定您到底存储了什么,但听起来使用共享首选项可能会很好。 Data Storage 上的这个页面解释了一些更永久地存储数据的不同方法,包括共享首选项。

        【讨论】:

        • 应用程序没有被杀死,因为如果是这样,我的静态变量将被重新创建,因为如果应用程序被破坏,那么当它被重新创建时,将调用 MyApplication 的 onCreate() 方法。
        【解决方案7】:
        1. 你不能。 Android 需要不时释放内存。想象一下,如果所有应用程序都有大量应该永久驻留的静态数据 - 您将如何将其放入内存中?这是一部手机。它没有虚拟内存。

        2. (和 3):任何旨在持久化的内容都需要通过 SharedPreferences、Sqlite 数据库或文件进行存储。

        【讨论】:

        • 好的,谢谢,但我无法更改我的应用程序现在的工作方式。但如果可以的话,我肯定会改变它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-05
        相关资源
        最近更新 更多