【问题标题】:How do I serialize an object and save it to a file in Android?如何序列化对象并将其保存到 Android 中的文件中?
【发布时间】:2011-05-06 08:20:38
【问题描述】:

假设我有一些简单的类,一旦它被实例化为一个对象,我希望能够将其内容序列化到一个文件中,并通过稍后加载该文件来检索它......我不知道在哪里从这里开始,我需要做什么才能将此对象序列化为文件?

public class SimpleClass {
   public string name;
   public int id;
   public void save() {
       /* wtf do I do here? */
   }
   public static SimpleClass load(String file) {
       /* what about here? */
   }
}

这可能是世界上最简单的问题,因为在 .NET 中这是一个非常简单的任务,但在 Android 中我还很新,所以我完全迷路了。

【问题讨论】:

    标签: android serialization file-io


    【解决方案1】:

    保存(无异常处理代码):

    FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
    ObjectOutputStream os = new ObjectOutputStream(fos);
    os.writeObject(this);
    os.close();
    fos.close();
    

    正在加载(无异常处理代码):

    FileInputStream fis = context.openFileInput(fileName);
    ObjectInputStream is = new ObjectInputStream(fis);
    SimpleClass simpleClass = (SimpleClass) is.readObject();
    is.close();
    fis.close();
    

    【讨论】:

    • 非常有用。您能否解释一下我们是否必须将类序列化为目标文件。
    • 如果您使用 Serializable 接口,此功能会隐式添加到您的类中。如果你想要的只是简单的对象序列化,那就是我会使用的。它也非常容易实现。 developer.android.com/reference/java/io/Serializable.html
    • +1,要保存多个对象,需要技巧:stackoverflow.com/a/1195078/1321401
    • 是否也应该调用 fos.close() 和 fis.close() ?
    • 我推荐Paper。它使用 Kryo 序列化,比普通的 Java 序列化要快得多。
    【解决方案2】:

    我已经尝试了这 2 个选项(读/写),使用普通对象、对象数组(150 个对象)、地图:

    选项1:

    FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
    ObjectOutputStream os = new ObjectOutputStream(fos);
    os.writeObject(this);
    os.close();
    

    选项2:

    SharedPreferences mPrefs=app.getSharedPreferences(app.getApplicationInfo().name, Context.MODE_PRIVATE);
    SharedPreferences.Editor ed=mPrefs.edit();
    Gson gson = new Gson(); 
    ed.putString("myObjectKey", gson.toJson(objectToSave));
    ed.commit();
    

    选项 2 比选项 1 快两倍

    选项2的不便之处在于您必须编写特定的代码才能读取:

    Gson gson = new Gson();
    JsonParser parser=new JsonParser();
    //object arr example
    JsonArray arr=parser.parse(mPrefs.getString("myArrKey", null)).getAsJsonArray();
    events=new Event[arr.size()];
    int i=0;
    for (JsonElement jsonElement : arr)
        events[i++]=gson.fromJson(jsonElement, Event.class);
    //Object example
    pagination=gson.fromJson(parser.parse(jsonPagination).getAsJsonObject(), Pagination.class);
    

    【讨论】:

    • 为什么说选项 2 更快?也许是因为 SharedPreferences 保存在内存中,而您测量的时间不包括将其保存到文件系统?我问这个是因为我想序列化到对象流必须比 JSON 字符串更有效。
    • 我也不知道为什么,但是官方序列化kotlin文档中似乎也使用了Json。为什么 JSON 是默认的...
    【解决方案3】:

    我刚刚创建了一个类来处理泛型,因此它可以用于所有可序列化的对象类型:

    public class SerializableManager {
    
        /**
         * Saves a serializable object.
         *
         * @param context The application context.
         * @param objectToSave The object to save.
         * @param fileName The name of the file.
         * @param <T> The type of the object.
         */
    
        public static <T extends Serializable> void saveSerializable(Context context, T objectToSave, String fileName) {
            try {
                FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    
                objectOutputStream.writeObject(objectToSave);
    
                objectOutputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Loads a serializable object.
         *
         * @param context The application context.
         * @param fileName The filename.
         * @param <T> The object type.
         *
         * @return the serializable object.
         */
    
        public static<T extends Serializable> T readSerializable(Context context, String fileName) {
            T objectToReturn = null;
    
            try {
                FileInputStream fileInputStream = context.openFileInput(fileName);
                ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
                objectToReturn = (T) objectInputStream.readObject();
    
                objectInputStream.close();
                fileInputStream.close();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            return objectToReturn;
        }
    
        /**
         * Removes a specified file.
         *
         * @param context The application context.
         * @param filename The name of the file.
         */
    
        public static void removeSerializable(Context context, String filename) {
            context.deleteFile(filename);
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      带有错误处理和添加的文件流关闭的完整代码。将它添加到您希望能够序列化和反序列化的类中。在我的例子中,类名是CreateResumeForm。您应该将其更改为您自己的类名。 Android interface Serializable 不足以将您的对象保存到文件中,它只会创建流。

      // Constant with a file name
      public static String fileName = "createResumeForm.ser";
      
      // Serializes an object and saves it to a file
      public void saveToFile(Context context) {
          try {
              FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
              objectOutputStream.writeObject(this);
              objectOutputStream.close();
              fileOutputStream.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      
      
      // Creates an object by reading it from a file
      public static CreateResumeForm readFromFile(Context context) {
          CreateResumeForm createResumeForm = null;
          try {
              FileInputStream fileInputStream = context.openFileInput(fileName);
              ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
              createResumeForm = (CreateResumeForm) objectInputStream.readObject();
              objectInputStream.close();
              fileInputStream.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
          catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          return createResumeForm;
      }
      

      在你的Activity 中这样使用它:

      form = CreateResumeForm.readFromFile(this);
      

      【讨论】:

        【解决方案5】:

        我使用 SharePrefrences:

        package myapps.serializedemo;
        
        import android.content.Context;
        import android.content.SharedPreferences;
        import android.support.v7.app.AppCompatActivity;
        import android.os.Bundle;
        import android.util.Log;
        
        import java.io.IOException;
        import java.util.ArrayList;
        
        public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        
        //Create the SharedPreferences
            SharedPreferences sharedPreferences = this.getSharedPreferences("myapps.serilizerdemo", Context.MODE_PRIVATE);
            ArrayList<String> friends = new ArrayList<>();
            friends.add("Jack");
            friends.add("Joe");
            try {
        
         //Write / Serialize
         sharedPreferences.edit().putString("friends",
            ObjectSerializer.serialize(friends)).apply();
            } catch (IOException e) {
                e.printStackTrace();
            }
        //READ BACK
            ArrayList<String> newFriends = new ArrayList<>();
            try {
                newFriends = (ArrayList<String>) ObjectSerializer.deserialize(
                        sharedPreferences.getString("friends", ObjectSerializer.serialize(new ArrayList<String>())));
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.i("***NewFriends", newFriends.toString());
        }
        }
        

        【讨论】:

          【解决方案6】:

          您必须在您的程序中添加一个 ObjectSerialization 类,以下可能会起作用

              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 ObjectSerializer {
          
          public static String serialize(Serializable obj) throws IOException {
              if (obj == null) return "";
              try {
                  ByteArrayOutputStream serialObj = new ByteArrayOutputStream();
                  ObjectOutputStream objStream = new ObjectOutputStream(serialObj);
                  objStream.writeObject(obj);
                  objStream.close();
                  return encodeBytes(serialObj.toByteArray());
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }
          
          public static Object deserialize(String str) throws IOException {
              if (str == null || str.length() == 0) return null;
              try {
                  ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str));
                  ObjectInputStream objStream = new ObjectInputStream(serialObj);
                  return objStream.readObject();
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }
          
          public static String encodeBytes(byte[] bytes) {
              StringBuffer strBuf = new StringBuffer();
          
              for (int i = 0; i < bytes.length; i++) {
                  strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
                  strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
              }
          
              return strBuf.toString();
          }
          
          public static byte[] decodeBytes(String str) {
              byte[] bytes = new byte[str.length() / 2];
              for (int i = 0; i < str.length(); i+=2) {
                  char c = str.charAt(i);
                  bytes[i/2] = (byte) ((c - 'a') << 4);
                  c = str.charAt(i+1);
                  bytes[i/2] += (c - 'a');
              }
              return bytes;
          }
          

          }

          如果您使用 SharedPreferences 存储数组而不是使用以下内容:-

          SharedPreferences sharedPreferences = this.getSharedPreferences(getPackageName(),MODE_PRIVATE);
          

          序列化:-

          sharedPreferences.putString("name",ObjectSerializer.serialize(array));
          

          反序列化:-

          newarray = (CAST_IT_TO_PROPER_TYPE) ObjectSerializer.deSerialize(sharedPreferences.getString(name),null);
          

          【讨论】:

            猜你喜欢
            • 2013-11-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多