使用SharedPreferences保存字节数组

59

我在我的安卓应用程序中创建了一个 byte [] array,现在想使用Android提供的SharedPreferences来存储它,并在下次启动我的应用程序时重新获取它。怎样做呢?


1
你尝试过什么吗? - Ye Lin Aung
5个回答

127

你可以使用android.util.Base64在SharedPreferences中保存字节数组。

保存时:

String saveThis = Base64.encodeToString(array, Base64.DEFAULT);

加载中:

byte[] array = Base64.decode(stringFromSharedPrefs, Base64.DEFAULT);

24
非常好的复制粘贴解决方案,但我个人使用Base64.NO_WRAP而不是Base64.DEFAULT。在我的看法中,没有必要在首选项中使用换行符。 - rekire

30
当将数据转换为Base64字符串时,实际上会增加数据的大小

Base64编码二进制数据的最终大小等于原始数据大小的1.37倍+814个字节(用于标头)。

使用Charsets.ISO_8859_1在SharedPreferences中保存byte[]更快且内存效率更高。
private static final String PREF_NAME = "SharedPreferences_Name";
private static final String DATA_NAME = "BytesData_Name";

public static byte[] getBytes(Context ctx) {
    SharedPreferences prefs = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    String str = prefs.getString(DATA_NAME, null);
    if (str != null) {
        return str.getBytes(Charsets.ISO_8859_1);
    }
    return null;
}

public static void setBytes(Context ctx, byte[] bytes) {
    SharedPreferences prefs = ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    SharedPreferences.Editor e = prefs.edit();
    e.putString(DATA_NAME, new String(bytes, Charsets.ISO_8859_1));
    e.commit();
}
  • ISO_8859_1可以保留您的数据(不像UTF-8和UTF-16)。
  • 如果您要在应用程序外传输这些字节,例如使用JSON,则必须在序列化之前将byte[]转换为Base64。
  • JSON无法理解ISO_8859_1将使用的奇怪字符。

提示:如果您想节省更多空间(例如在保存大量byte[]时),请在将其转换为任何格式(ISO或Base64)之前压缩byte[]。


1
如果你的数组非常大,那么你不应该使用SharedPreferences。根据保存键值对:"如果你有一个相对较小的键值集合需要保存,应该使用SharedPreferences API。" - Edward Brey
ISO_8859_1在Android中是否是8位清洁的行为有没有任何记录? - Edward Brey
@EdwardBrey 我已经包含了一个相关链接,并且实现了一段可在 Android 和 iOS 上运行的代码,用于一家医疗公司 - 经过测试并且可以正常工作 - 你可以自己试试 :) - Ariel Yust

22

你可以尝试将它保存为一个String

存储数组:

SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("myByteArray", Arrays.toString(array));

获取数组:

SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
String stringArray = settings.getString("myByteArray", null);

if (stringArray != null) {
    String[] split = stringArray.substring(1, stringArray.length()-1).split(", ");
    byte[] array = new byte[split.length];
    for (int i = 0; i < split.length; i++) {
      array[i] = Byte.parseByte(split[i]);
    }
}

1
无法工作。还有,你为什么要这样做 'String[] split = stringArray.substring(1, stringArray.length()-1).split(", ");'? - user2453055
1
你能详细说明一下为什么它不起作用吗?在我的端上,代码测试正常。至于子字符串,是因为当你调用Arrays.toString(array)时,它会创建一个形如"[1, 2, 3, 4]"的字符串。所以substring()是为了去掉方括号,而split()则是为了得到一个包含单个数字的字符串数组,这样我们就可以轻松地将它们解析成字节。 - Francis
当我保存一张图片的byte[],然后过一段时间想从sharedPreferences中检索它时,应用程序会冻结5-15或20秒(根据图像大小)。如果是大图像,则需要25-30秒。因此,我认为最好的方法是将其保存在文件中。 - Hayk Mkrtchyan
SharedPreferences 不适合存储大量数据,因为它是基于文件系统上的简单 XML 文件。此外,如果您的应用程序冻结了,可能是因为您在主 UI 线程中运行操作? - Francis

4

我无法给Ariel Yust的回答点赞,但它完美地解决了问题。

其他答案(如Base64编码器)对于我的最低API版本不可用,或者不能保留原始值(在加密/解密数据时可能会有问题)

作为补充,我建议在kotlin中使用扩展:

val String.toPreservedByteArray: ByteArray
get() {
    return this.toByteArray(Charsets.ISO_8859_1)
}

val ByteArray.toPreservedString: String
get() {
    return String(this, Charsets.ISO_8859_1)
}

那么你只需在字符串上调用它:
val string = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE).getString("string", "") ?: ""
val byteArray = string.toPreservedByteArray

谢谢,我很高兴它在 Kotlin 上也能正常工作。 - Ariel Yust

0

在共享首选项中保存数组:

public static boolean saveArray()
{
    SharedPreferences sp = SharedPreferences.getDefaultSharedPreferences(this);
    SharedPreferences.Editor mEdit1 = sp.edit();
    mEdit1.putInt("Status_size", byteArr.size()); /* byteArr is an array */ 

    for(int i=0;i<byteArr.size();i++)  
    {
        mEdit1.remove("Status_" + i);
        mEdit1.putString("Status_" + i, byteArr.get(i));  
    }

    return mEdit1.commit();     
}

从共享首选项中加载数组数据:

public static void loadArray(Context mContext)
{  
    Shared Preferences mSharedPreference1 = PreferenceManager.getDefaultSharedPreferences(mContext);
    byteArr.clear();
    int size = mSharedPreference1.getInt("Status_size", 0);  

    for(int i=0;i<size;i++) 
    {
        byteArr.add(mSharedPreference1.getString("Status_" + i, null));
    }
}

实现并调用上述两个函数。希望以上代码能够帮助到您。


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