ObjectInputStream readObject 导致 RoundingMode.ordinal NullPointerException

Val*_*rio 6 java android

编辑:这似乎是一个与 Android Pie (api 28) 相关的问题。似乎适用于以前的版本(在 27、26、25 上测试过)。


我在这个 Android 代码上工作了很长时间,我注意到最近当我在磁盘上保存数据时,我收到这个错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.math.RoundingMode.ordinal()' on a null object reference
Run Code Online (Sandbox Code Playgroud)

这就是我将数据写入磁盘的方式

private void SaveDataToDisk() {
    try {
        FileOutputStream fos = this.weakActivity.get().openFileOutput(this.FILENAME, Context.MODE_PRIVATE);
        if (fos != null) {
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(this.datastore);
            os.close();
            fos.close();
        }
    } catch (Exception ex) {
            ErrorManager.TrapThrow(ex, this.weakActivity.get());
    }
}
Run Code Online (Sandbox Code Playgroud)

this.datastore 是一个由多个其他对象(非常大的数量)组成的复杂对象。

这就是我在需要时读回数据的方式

private void LoadDataFromDisk() {
    try {
        if (this.weakActivity.get().getFileStreamPath(this.FILENAME).exists()) {
            FileInputStream fis = this.weakActivity.get().openFileInput(this.FILENAME);
            BufferedInputStream bis = new BufferedInputStream(fis);
            ObjectInputStream is = new ObjectInputStream(bis);
            try {
                this.datastore = (DataStore) is.readObject();
            } catch (Exception ex) {
                this.datastore = new DataStore();
            }
            is.close();
            fis.close();
        }
    } catch (Exception ex) {
        ErrorManager.TrapThrow(ex, this.weakActivity.get());
    }
}
Run Code Online (Sandbox Code Playgroud)

想象一下全新安装的应用程序。第一次 LoadDataFromDisk 什么都不做。稍后,应用程序会在磁盘上写入一些内容。当应用程序再次调用 LoadDataFromDisk 时,它读取正确。然后,例如,重新启动应用程序:当达到 LoadDataFromDisk 时,特别是

this.datastore = (DataStore) is.readObject();
Run Code Online (Sandbox Code Playgroud)

我收到上述错误,并回退到一个新的 DataStore 对象,以保持应用程序正常工作。

为什么不总是?数据在读取后似乎已损坏。我可以在 AVD 和手机上重现。

任何帮助表示赞赏

小智 9

我们发现这是由DataFormatter依赖于java.text.DecimalFormat. 当我们去反序列化对象时(有时但并非总是如此,但显然取决于包含对象在Activityextras之间传递的次数),包含序列化容器的整个 Extras 集合无效,并导致应用程序与RoundingMode.ordinal()NPE崩溃。

显然,DecimalFormat该类在 Android 9/Pie 中不再适合序列化,因为在我们的例子中,它就像标记包含Serializable对象的DataFormatteras实例一样简单,transient问题就消失了。

很抱歉没有准备好更好地剖析这个问题,但这解决了我们这个错误的问题。

  • 更新:我可以确认这是正确的方法。谢谢! (2认同)