将捆绑保存到文件

6
  Bundle bundle;
  //set data to bundle
  //......


  File file = new File(context.getFilesDir().getAbsolutePath()  + "/data/");
                FileOutputStream fos;
                try {
                     fos = new FileOutputStream(file);
                     //fos.write
                     fos.close();
                } catch (FileNotFoundException exp1) {
                    exp1.printStackTrace();
                } catch ( IOException exp2) {
                    exp2.printStackTrace();
                }

我有上述的代码。我想要做的就是将bundle保存到文件中。我找到了write方法,但我只能传递byte[]而不能传递bundle。我试图将bundle转换为byte[],但没有成功。我该怎么做才能让它工作?最有效的方法是什么?


你为什么要尝试将bundle写入文件呢?为什么不直接将bundle的数据写入文件呢? - Antrromet
请解释为什么你需要这个。 - Leonidos
7个回答

5

没有一种通用的方法可以从持久存储中保存和恢复Bundle。这是因为Parcel类不提供任何Android版本兼容性保证。因此,最好不要对其进行序列化。

但是,如果您真的想要,可以通过Parceable接口将Bundle序列化。将bundle转换为Parcel(writeToParcel()/readFromParcel()),然后使用Parcel的marshall()和unmarshall()方法获取byte[]。将byte Array保存/加载到文件中。但是有可能,如果用户将Android OS更新到新版本,您将无法恢复数据。

有一种合法但非常痛苦且不可靠的方法可以使用ObjectOutput/InputStream序列化bundle。(获取所有键,遍历键并将可序列化的key=value对保存到文件中,然后从文件中读取key=value对,确定值的类型,通过适当的putXXX(key, value)方法将数据放回Bundle) 但这不值得。

我建议您将自定义可序列化结构放入Bundle中以存储其中的所有所需值,并仅从文件中保存/加载此结构。

或者找到更好的方式来管理数据,而不使用Bundle。


1
你绝不应该这样做。从 Parcel.marshall() 的文档中得知,此处检索的数据不得放置在任何类型的持久性存储(本地磁盘、网络等)中。为此,您应使用标准序列化或其他一般序列化机制。 Parcel marshalled 表示针对本地 IPC 进行了高度优化,因此不会尝试与在平台的不同版本中创建的数据保持兼容性。 - Vladimir Mironov
1
@vmironov 那你建议我们用什么来序列化呢? - Alex Dowining
是的,如果用户有时会更新Android版本,那么您可能无法恢复包裹。因此,请不要使用这种方式保存关键数据。 - Leonidos

4
我不喜欢我上面评论中代码的格式,所以这是你应该如何读取它的方式:
像这样阅读:
try {
    FileInputStream fis = openFileInput(localFilename);
    byte[] array = new byte[(int) fis.getChannel().size()];
    fis.read(array, 0, array.length);
    fis.close();
    parcel.unmarshall(array, 0, array.length);
    parcel.setDataPosition(0);
    Bundle out = parcel.readBundle();
    out.putAll(out);
} catch (FileNotFoundException fnfe) {
} catch (IOException ioe) {
} finally {
    parcel.recycle();
}

1
非常感谢setDataPosition()的提示!谁能知道它必须被调用! - WindRider
不要这样做。https://developer.android.com/reference/android/os/Parcel.html说“将任何Parcel数据放入持久存储中是不合适的”。 - gladed

3
Bundle in=yourBundle;
FileOutputStream fos = context.openFileOutput(localFilename, Context.MODE_PRIVATE);
Parcel p = Parcel.obtain(); //creating empty parcel object
in.writeToParcel(p, 0); //saving bundle as parcel 
fos.write(p.marshall()); //writing parcel to file
fos.flush();
fos.close();

对不起,这是我的错误。我们正在将Bundle保存到Parcel对象中。 - Nirav Tukadiya
以以下方式阅读:FileInputStream fis = openFileInput(localFilename); byte[] array = new byte[(int) fis.getChannel().size()]; fis.read(array, 0, array.length); fis.close(); parcel.unmarshall(array, 0, array.length); parcel.setDataPosition(0); Bundle out = parcel.readBundle(); out.putAll(out); parcel.recycle(); - videogameboy76

0
你可以像这样做:
public void write(String fileName, Bundle bundle)
    {
        File root = Environment.getExternalStorageDirectory();
        File outDir = new File(root.getAbsolutePath() + File.separator + "My Bundle");
        if (!outDir.isDirectory())
        {
            outDir.mkdir();
        }
        try
        {
            if (!outDir.isDirectory())
            {
                throw new IOException("Unable to create directory My bundle. Maybe the SD card is mounted?");


    }
        File outputFile = new File(outDir, fileName);
        writer = new BufferedWriter(new FileWriter(outputFile));
        String value=bundle.getString("key");
        writer.write(value);
        Toast.makeText(context.getApplicationContext(), "Report successfully saved to: " + outputFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
        writer.close();
    } catch (IOException e)
    {
        Log.w("error", e.getMessage(), e);
        Toast.makeText(context, e.getMessage() + " Unable to write to external storage.", Toast.LENGTH_LONG).show();
    }

}

这里的想法很简单。您将Bundle传递给此方法,然后提取其中包含的任何数据(在本例中,我们有一个带有键key的字符串),然后将其写入文件。


0

这里有一些函数可以帮助你将 Bundle 转换为 JSONObject。需要注意的是,只有当 Bundle 中仅包含 intString 时,它才起作用。

public static JSONObject bundleToJsonObject(Bundle bundle) {
    try {
        JSONObject output = new JSONObject();
        for( String key : bundle.keySet() ){
            Object object = bundle.get(key);
            if(object instanceof Integer || object instanceof String)
                    output.put(key, object);
            else
                throw new RuntimeException("only Integer and String can be extracted");
        }
        return output;
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}

public static Bundle JsonObjectToBundle(JSONObject jsonObject) {
    try {
        Bundle bundle = new Bundle();
        Iterator<?> keys = jsonObject.keys();
        while( keys.hasNext() ){
            String key = (String)keys.next();
            Object object = jsonObject.get(key);
            if(object instanceof String)
                bundle.putString(key, (String) object);
            else if(object instanceof Integer)
                bundle.putInt(key, (Integer) object);
            else
                throw new RuntimeException("only Integer and String can be re-extracted");
        }
        return bundle;
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}

0

无法将 Bundle 保存到本地文件,否则会出现非序列化异常。可能存在其他存储方式。在读取和构造原始对象后无法保证完全一致。


0

我认为最好的想法是使用静态序列化或所有内容,因为Bundle可以从键迭代,在另一侧进行序列化和取消序列化,然后可以使用JSON或任何其他东西。例如,如果您在服务器和接收器中使用相同的类,则...

bundle->可序列化对象-> JSON->文件->可序列化对象-> bundle

任何操作系统版本都可以保证工作


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接