Android将自定义对象写入文件

时间:2014-07-23 13:12:56

标签: android io android-file

我有一个实现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

1 个答案:

答案 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。