我想序列化一个Bundle对象,但似乎无法找到一种简单的方法。使用Parcel似乎不是一个选项,因为我想将序列化数据存储到文件中。
关于如何做到这一点的任何想法?
我想要这个的原因是保存和恢复我的活动状态,也就是当它被用户杀死时。我已经创建了一个Bundle,其中包含我要保存在onSaveInstanceState中的状态。但是当活动被SYSTEM杀死时,android只保留这个Bundle。当用户杀死活动时,我需要自己存储它。因此,我想将其序列化并存储到文件中。当然,如果你有任何其他方式来完成同样的事情,我也会感激。
编辑: 我决定将我的状态编码为JSONObject而不是Bundle。然后可以将JSON对象作为Serializable放入Bundle中,或者存储到文件中。可能不是最有效的方式,但它很简单,似乎工作正常。
答案 0 :(得分:7)
将任何Parcelable存储到文件中非常简单:
FileOutputStream fos = context.openFileOutput(localFilename, Context.MODE_PRIVATE);
Parcel p = Parcel.obtain(); // i make an empty one here, but you can use yours
fos.write(p.marshall());
fos.flush();
fos.close();
享受!
答案 1 :(得分:6)
我使用SharedPreferences来解决这个限制,它使用与Bundle类相同的putXXX()和getXXX()样式来存储和检索数据,如果你使用了Bundle,它实现起来相对简单之前。
所以在onCreate我有这样的支票
if(savedInstanceState != null)
{
loadGameDataFromSavedInstanceState(savedInstanceState);
}
else
{
loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE));
}
我将游戏数据保存到onSaveInstanceState()中的Bundle,并从onRestoreInstanceState()
中的Bundle加载数据和
我还将游戏数据保存到onPause()中的SharedPreferences,并从onResume()
中的SharedPreferences加载数据onPause()
{
// get a SharedPreferences editor for storing game data to
SharedPreferences.Editor mySharedPreferences = getPreferences(MODE_PRIVATE).edit();
// call a function to actually store the game data
saveGameDataToSharedPreferences(mySharedPreferences);
// make sure you call mySharedPreferences.commit() at the end of your function
}
onResume()
{
loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE));
}
如果有些人认为这是对SharedPreferences的错误使用,我不会感到惊讶,但它完成了工作。我已经在我的所有游戏中使用这种方法(近200万次下载)超过一年,并且它可以工作。
答案 2 :(得分:5)
将其转换为SharedPreferences:
private void saveToPreferences(Bundle in) {
Parcel parcel = Parcel.obtain();
String serialized = null;
try {
in.writeToParcel(parcel, 0);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.write(parcel.marshall(), bos);
serialized = Base64.encodeToString(bos.toByteArray(), 0);
} catch (IOException e) {
Log.e(getClass().getSimpleName(), e.toString(), e);
} finally {
parcel.recycle();
}
if (serialized != null) {
SharedPreferences settings = getSharedPreferences(PREFS, 0);
Editor editor = settings.edit();
editor.putString("parcel", serialized);
editor.commit();
}
}
private Bundle restoreFromPreferences() {
Bundle bundle = null;
SharedPreferences settings = getSharedPreferences(PREFS, 0);
String serialized = settings.getString("parcel", null);
if (serialized != null) {
Parcel parcel = Parcel.obtain();
try {
byte[] data = Base64.decode(serialized, 0);
parcel.unmarshall(data, 0, data.length);
parcel.setDataPosition(0);
bundle = parcel.readBundle();
} finally {
parcel.recycle();
}
}
return bundle;
}
答案 3 :(得分:0)
如果您想将其存储在持久存储中,则不能依赖于parcelable或serializable机制。你必须自己做,下面是我通常这样做的方式:
private static final Gson sGson = new GsonBuilder().create();
private static final String CHARSET = "UTF-8";
// taken from http://www.javacamp.org/javaI/primitiveTypes.html
private static final int BOOLEAN_LEN = 1;
private static final int INTEGER_LEN = 4;
private static final int DOUBLE_LEN = 8;
public static byte[] serializeBundle(Bundle bundle) {
try {
List<SerializedItem> list = new ArrayList<>();
if (bundle != null) {
Set<String> keys = bundle.keySet();
for (String key : keys) {
Object value = bundle.get(key);
if (value == null) continue;
SerializedItem bis = new SerializedItem();
bis.setClassName(value.getClass().getCanonicalName());
bis.setKey(key);
if (value instanceof String)
bis.setValue(((String) value).getBytes(CHARSET));
else if (value instanceof SpannableString) {
String str = Html.toHtml((Spanned) value);
bis.setValue(str.getBytes(CHARSET));
} else if (value.getClass().isAssignableFrom(Integer.class)) {
ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN);
b.putInt((Integer) value);
bis.setValue(b.array());
} else if (value.getClass().isAssignableFrom(Double.class)) {
ByteBuffer b = ByteBuffer.allocate(DOUBLE_LEN);
b.putDouble((Double) value);
bis.setValue(b.array());
} else if (value.getClass().isAssignableFrom(Boolean.class)) {
ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN);
boolean v = (boolean) value;
b.putInt(v ? 1 : 0);
bis.setValue(b.array());
} else
continue; // we do nothing in this case since there is amazing amount of stuff you can put into bundle but if you want something specific you can still add it
// throw new IllegalStateException("Unable to serialize class + " + value.getClass().getCanonicalName());
list.add(bis);
}
return sGson.toJson(list).getBytes(CHARSET);
}
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalStateException("Unable to serialize " + bundle);
}
public static Bundle deserializeBundle(byte[] toDeserialize) {
try {
Bundle bundle = new Bundle();
if (toDeserialize != null) {
SerializedItem[] bundleItems = new Gson().fromJson(new String(toDeserialize, CHARSET), SerializedItem[].class);
for (SerializedItem bis : bundleItems) {
if (String.class.getCanonicalName().equals(bis.getClassName()))
bundle.putString(bis.getKey(), new String(bis.getValue()));
else if (Integer.class.getCanonicalName().equals(bis.getClassName()))
bundle.putInt(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getInt());
else if (Double.class.getCanonicalName().equals(bis.getClassName()))
bundle.putDouble(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getDouble());
else if (Boolean.class.getCanonicalName().equals(bis.getClassName())) {
int v = ByteBuffer.wrap(bis.getValue()).getInt();
bundle.putBoolean(bis.getKey(), v == 1);
} else
throw new IllegalStateException("Unable to deserialize class " + bis.getClassName());
}
}
return bundle;
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalStateException("Unable to deserialize " + Arrays.toString(toDeserialize));
}
您将数据表示为字节数组,您可以轻松地将其存储到文件中,通过网络发送或使用ormLite存储到sql数据库,如下所示:
@DatabaseField(dataType = DataType.BYTE_ARRAY)
private byte[] mRawBundle;
和SerializedItem:
public class SerializedItem {
private String mClassName;
private String mKey;
private byte[] mValue;
// + getters and setters
}
PS:上面的代码依赖于Gson库(这很常见,只是为了让你知道)。