我有一个实现Record
的自定义对象类Parcelable
,我正在通过ListView
创建ArrayAdapter<Record>
我希望能够保存该列表以便它下次用户打开应用程序时自动加载。该列表是动态填充的,每次添加记录时我都会调用我的save方法。然后我有一个SharedPreference
,其布尔值设置为true,这样我就知道用户已经保存了一些数据,以便在下次打开应用程序时加载。这是我的保存和加载方法:
public void writeRecordsToFile(ArrayAdapter<Record> records) {
String fileName = Environment.getExternalStorageDirectory().getPath() + "/records.dat";
try {
File file = new File(fileName);
if(!file.exists()){
file.createNewFile();
}
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file));
stream.writeObject(records);
stream.flush();
stream.close();
}
catch (IOException e){
Log.e("MyApp","IO Exception: " + e);
}
writeSavedState();
}
writeSavedState()
适用于我的SP
public void readRecordsList() {
String fileName = Environment.getExternalStorageDirectory().getPath() + "/records.dat";
try {
ObjectInputStream inputStream = new ObjectInputStream(getApplicationContext().openFileInput(fileName));
adapter = (ArrayAdapter<Record>)inputStream.readObject();
inputStream.close();
}
catch (Exception e){
Log.e("MyApp" , "File Not Found: " + e);
}
}
当我第一次打开应用程序时,我收到一条消息:
E/MyApp﹕ File Not Found: java.lang.IllegalArgumentException: File /storage/emulated/0/records.dat contains a path separator
然后当我在列表中添加Record
时,我收到消息:
E/MyApp﹕ IO Exception: java.io.IOException: open failed: EACCES (Permission denied)
我假设第二条消息是因为第一条消息而得到的。这是我第一次使用Android中的I / O,所以任何帮助将不胜感激!
修改
在向清单添加权限后,我现在只收到错误:
E/MyApp﹕ IO Exception: java.io.NotSerializableException: android.widget.ArrayAdapter
正如我所说,我的自定义对象为Parcelable
,其余部分正在我的MainActivity
中完成。我是否需要创建一个Serializable
的新课程来构建我的ArrayAdapter
?
答案 0 :(得分:2)
我建议以私人模式将记录保存在内部存储中,只能由您的应用访问。如果您将其存储在外部存储中,则无法保证下次加载应用时它可用。
此外,您应该保存记录对象数组而不是ArrayAdapter对象。
Parcel和Parcelable非常快,但它的文档说你不能将它用于存储的通用序列化,因为实现因Android的不同版本而异(即操作系统更新可能会破坏依赖它的应用程序) 。因此,在这种情况下使用Serializable而不是Parcalable(来自this SO线程)
您可以使用全局变量将数据从一个活动传递到另一个活动。当app开始使用扩展Applicaion类的全局类时,你也可以读/写记录。
您可以尝试以下代码,
public class GlobalClass extends Application {
public static Object objectToBePassed; // global variable
final static private RECORDS_FILENAME = "myRecords.txt"
@Override
public void onCreate(){
super.onCreate();
readRecordsFromFile(); // read records when app starts
}
public boolean writeRecordsToFile(ArrayList<Record> records){
FileOutputStream fos;
ObjectOutputStream oos=null;
try{
fos = getApplicationContext().openFileOutput(RECORDS_FILENAME, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(records);
oos.close();
return true;
}catch(Exception e){
Log.e(getClassName(), "Cant save records"+e.getMessage());
return false;
}
finally{
if(oos!=null)
try{
oos.close();
}catch(Exception e){
Log.e(getClassName(), "Error while closing stream "+e.getMessage());
}
}
}
private boolean readRecordsFromFile(){
FileInputStream fin;
ObjectInputStream ois=null;
try{
fin = getApplicationContext().openFileInput(RECORDS_FILENAME);
ois = new ObjectInputStream(fin);
ArrayList<Record> records = (ArrayList<Record>) ois.readObject();
ois.close();
Log.v(getClassName(), "Records read successfully");
return true;
}catch(Exception e){
Log.e(getClassName(), "Cant read saved records"+e.getMessage());
return false;
}
finally{
if(ois!=null)
try{
ois.close();
}catch(Exception e){
Log.e(getClassName(), "Error in closing stream while reading records"+e.getMessage());
}
}
}
}
因此,要将任何对象从活动A传递到活动B,请在活动A中使用以下代码,
Intent intent = new Intent(this,B.class);
GlobalClass.objectToBePassed = obj;
startActivity(intent);
活动B,
MyClass object = (MyClass) GlobalClass.objectToBePassed;
所以要传递一个Record类对象,用Record替换MyClass。