将Bundle保存到SharedPreferences

Dan*_*Dan 22 android bundle save sharedpreferences

我已经竭尽全力让我的Android游戏的所有数据都适合saveInstanceState Bundle.共有很多数据,包括许多Parcelable对象.这可确保当应用程序暂停或方向更改时,重新创建的活动不会丢失任何数据.

但是,我刚刚发现savedInstanceState包显然不适合长期存储.所以我正在寻找一种方法,我可以调整我现有的保存方法作为长期解决方案,以便始终可以恢复游戏状态.

到目前为止,我听说过2个解决方案:

1)使用savedInstanceState包进行方向更改,但在应用程序需要完全关闭时还要包含SharedPrefs.

这看起来非常适得其反,因为它使用2种不同的完全方法来做同样的事情.此外,由于我的savedInstanceState Bundle使用Parcelable对象,因此我必须为这些对象中的每一个提供另一种方法,以使它们能够写入SharedPrefs.基本上很多重复和难以管理的代码.

2)序列化savedInstanceState Bundle并将其直接写入文件.

我对此持开放态度,但我实际上并不知道如何去做.但是,我仍然希望可能有更好的解决方案,因为我听说Android中的序列化"可笑/非常慢".

如果有人能为我提供解决方案,我将非常感激.

Sni*_*las 18

有趣的是,本周,Android Weekly发布了47个这个库: android复杂偏好.

它应该适合你.


Dan*_*Dan 4

我现在想出了自己的解决方案来解决这个问题,这是一种将 Bundles 保存到 SharedPreferences 的半自动方法。我说半自动是因为,虽然保存 Bundle 只需要一种方法,但再次检索数据并将其转回 Bundle 需要一些工作。

这是保存 Bundle 的代码:

SharedPreferences save = getSharedPreferences(SAVE, MODE_PRIVATE);
Editor ed = save.edit();
saveBundle(ed, "", gameState);

/**
 * Manually save a Bundle object to SharedPreferences.
 * @param ed
 * @param header
 * @param gameState
 */
private void saveBundle(Editor ed, String header, Bundle gameState) {
    Set<String> keySet = gameState.keySet();
    Iterator<String> it = keySet.iterator();

    while (it.hasNext()){
        key = it.next();
        o = gameState.get(key);
        if (o == null){
            ed.remove(header + key);
        } else if (o instanceof Integer){
            ed.putInt(header + key, (Integer) o);
        } else if (o instanceof Long){
            ed.putLong(header + key, (Long) o);
        } else if (o instanceof Boolean){
            ed.putBoolean(header + key, (Boolean) o);
        } else if (o instanceof CharSequence){
            ed.putString(header + key, ((CharSequence) o).toString());
        } else if (o instanceof Bundle){
            saveBundle(header + key, ((Bundle) o));
        }
    }

    ed.commit();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我只编写了我需要的类型的案例,但是如果您有还包含其他类型的捆绑包,那么这应该很容易适应。

此方法将递归地保存存储在给定 Bundle 内的其他 Bundle 对象。但是,它不适用于 Parcelable 对象,因此我必须更改 Parcelable 对象,使它们将自己存储到 Bundle 中。由于包裹和捆绑包非常相似,因此这并不太难。不幸的是,我认为捆绑包也可能比包裹稍微慢一些。

然后,我在所有以前的 Parcelable 对象中编写了构造函数,使它们能够从存储的 SharedPreferences 数据中重新捆绑自己。重建所需数据的密钥非常容易。假设您有以下数据结构:

Bundle b {
    KEY_X -> int x;
    KEY_Y -> Bundle y {
                 KEY_Z -> int z;
             }
}
Run Code Online (Sandbox Code Playgroud)

这些将保存到 SharedPreferences 中,如下所示:

KEY_X -> x
KEY_YKEY_Z -> z
Run Code Online (Sandbox Code Playgroud)

它可能不是世界上最漂亮的方法,但它确实有效,而且比其他方法花费的代码要少得多,因为现在我的 onSaveInstanceState 方法和 onPause 方法使用相同的技术。