编辑:这似乎是一个与 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问题就消失了。
很抱歉没有准备好更好地剖析这个问题,但这解决了我们这个错误的问题。