【发布时间】:2011-08-14 13:45:52
【问题描述】:
我知道 SharedPreferences 有 putString()、putFloat()、putLong()、putInt() 和 putBoolean()。但是我需要在SharedPreferences 中存储一个Serializable 类型的对象。我怎样才能做到这一点?
【问题讨论】:
标签: android serialization sharedpreferences
我知道 SharedPreferences 有 putString()、putFloat()、putLong()、putInt() 和 putBoolean()。但是我需要在SharedPreferences 中存储一个Serializable 类型的对象。我怎样才能做到这一点?
【问题讨论】:
标签: android serialization sharedpreferences
简而言之,您不能尝试将您的对象序列化为私有文件,这相当于同一件事。下面的示例类:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import android.app.Activity;
import android.content.Context;
/**
*
* Writes/reads an object to/from a private local file
*
*
*/
public class LocalPersistence {
/**
*
* @param context
* @param object
* @param filename
*/
public static void witeObjectToFile(Context context, Object object, String filename) {
ObjectOutputStream objectOut = null;
try {
FileOutputStream fileOut = context.openFileOutput(filename, Activity.MODE_PRIVATE);
objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(object);
fileOut.getFD().sync();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (objectOut != null) {
try {
objectOut.close();
} catch (IOException e) {
// do nowt
}
}
}
}
/**
*
* @param context
* @param filename
* @return
*/
public static Object readObjectFromFile(Context context, String filename) {
ObjectInputStream objectIn = null;
Object object = null;
try {
FileInputStream fileIn = context.getApplicationContext().openFileInput(filename);
objectIn = new ObjectInputStream(fileIn);
object = objectIn.readObject();
} catch (FileNotFoundException e) {
// Do nothing
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (objectIn != null) {
try {
objectIn.close();
} catch (IOException e) {
// do nowt
}
}
}
return object;
}
}
【讨论】:
filename 应该是绝对路径(例如:“/data/com.example.myapp/foobar.dat”),还是应该是相对路径(例如:“foobar.dat” ")?
公认的答案具有误导性,我们可以使用 GSON 将可序列化对象存储到 SharedPreferences 中。在google-gson 阅读有关它的更多信息。
您可以在 Gradle 文件中添加 GSON 依赖项:
compile 'com.google.code.gson:gson:2.7'
这里是sn-p:
首先,创建您常用的 sharedPreferences:
//Creating a shared preference
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
从可序列化对象保存到首选项:
Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(YourSerializableObject);
prefsEditor.putString("SerializableObject", json);
prefsEditor.commit();
从首选项中获取可序列化对象:
Gson gson = new Gson();
String json = mPrefs.getString("SerializableObject", "");
yourSerializableObject = gson.fromJson(json, YourSerializableObject.class);
【讨论】:
如果您的对象是简单的 POJO,您可以将对象转换为 JSON 字符串并使用 putString() 将其保存在共享首选项中。
【讨论】:
没有文件也可以。
我正在将信息序列化为 base64,这样我就可以将其作为字符串保存在首选项中。
以下代码将可序列化的对象序列化为 base64 字符串,反之亦然: 导入android.util.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ObjectSerializerHelper {
static public String objectToString(Serializable object) {
String encoded = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.close();
encoded = new String(Base64.encodeToString(byteArrayOutputStream.toByteArray(),0));
} catch (IOException e) {
e.printStackTrace();
}
return encoded;
}
@SuppressWarnings("unchecked")
static public Serializable stringToObject(String string){
byte[] bytes = Base64.decode(string,0);
Serializable object = null;
try {
ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream(bytes) );
object = (Serializable)objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
}
return object;
}
}
【讨论】:
public YourPojo getFromPreferences(Context context)和public void saveToPreferences(Context context),使用上面的两种方法,以及PreferenceManager.getDefaultSharedPreferences(context)
我们可以使用 Kotlin 创建一个易于使用的语法。
@Throws(JsonIOException::class)
fun Serializable.toJson(): String {
return Gson().toJson(this)
}
@Throws(JsonSyntaxException::class)
fun <T> String.to(type: Class<T>): T where T : Serializable {
return Gson().fromJson(this, type)
}
@Throws(JsonIOException::class)
fun SharedPreferences.Editor.putSerializable(key: String, o: Serializable?) = apply {
putString(key, o?.toJson())
}
@Throws(JsonSyntaxException::class)
fun <T> SharedPreferences.getSerializable(key: String, type: Class<T>): T? where T : Serializable {
return getString(key, null)?.to(type)
}
然后使用类似的get/put() 将任何Serializable 保存到SharedPreferences
这里有完整的要点Save Serializables in Shared Preferences with Kotlin and GSON
正如其他答案中提到的,当数据类的结构发生变化时,您可能必须考虑迁移。或者至少必须更改您用于存储的密钥。
【讨论】:
2020:如果要保存对象,那么最好使用 Proto DataStore 而不是 SharedPreferences。
与“旧”的 SharedPreferences 相比,它带来了很大的好处,即:
还有许多其他好处,例如保证一致性的事务 API。
【讨论】:
如果您的对象与嵌套对象很复杂,并且您有一天可能需要删除嵌套对象,那么这是一种不好的机制,因为您需要实施自己的迁移策略(除非丢弃所有数据都可以)。
如果是大量数据,这种机制缺乏事务支持。那你自己写吗?还是使用更合适的存储机制?我强烈建议使用更合适的存储机制,例如 SQLite DB 的文件系统。
【讨论】: