我有一个android应用程序,它显示出奇怪的行为。我有一个从文件反序列化对象的方法。下面是我使用的代码:
public static Object readData(Context context, String fileName)
{
synchronized (context) {
ObjectInputStream input = null;
Object object = null;
if (fileExists(context, fileName)) {
try {
input = new ObjectInputStream(context.openFileInput(fileName));
object = input.readObject();
Log.v(Constant.TAG, "Writable object has been loaded from file "+fileName);
} catch (IOException e) {
Log.e(Constant.TAG, e.getMessage(), e);
} catch (ClassNotFoundException e) {
Log.e(Constant.TAG, e.getMessage(), e);
} finally {
try {
if (input != null)
input.close();
} catch (IOException e) {
Log.e(Constant.TAG, e.getMessage(), e);
}
}
}
return object;
}
}
通常情况下,它工作得很好,但当有人最小化我的应用程序,并在一段时间后重新打开,它崩溃。从事故报告中我发现 IllegalArgumentException
在代码上方的下行中
object = input.readObject();
我查阅了 ObjectInputStream.readObject
但它没有说明在什么情况下它可以扔 IllegalArgumentException
.
这只发生在用户从后台带来应用程序时。它在应用程序启动时工作得非常好(我所说的启动是指应用程序没有运行,甚至在后台也没有运行)。
附:有一些车祸报告显示 ClassCastException
在同一行,这是更奇怪的,因为我不是演员,只是阅读成一个 Object
.
更新
堆栈跟踪
java.lang.RuntimeException:
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2423)
at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2483)
at android.app.ActivityThread.access$900 (ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1349)
at android.os.Handler.dispatchMessage (Handler.java:102)
at android.os.Looper.loop (Looper.java:148)
at android.app.ActivityThread.main (ActivityThread.java:5441)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:628)
Caused by: java.lang.IllegalArgumentException:
at java.lang.reflect.Field.set (Native Method)
at java.io.ObjectInputStream.readFieldValues (ObjectInputStream.java:1127)
at java.io.ObjectInputStream.defaultReadObject (ObjectInputStream.java:454)
at java.io.ObjectInputStream.readObjectForClass (ObjectInputStream.java:1345)
at java.io.ObjectInputStream.readHierarchy (ObjectInputStream.java:1242)
at java.io.ObjectInputStream.readNewObject (ObjectInputStream.java:1835)
at java.io.ObjectInputStream.readNonPrimitiveContent (ObjectInputStream.java:761)
at java.io.ObjectInputStream.readObject (ObjectInputStream.java:1983)
at java.io.ObjectInputStream.readObject (ObjectInputStream.java:1940)
at com.pixyfisocial.pixyfi.util.IOUtil.readData (IOUtil.java:245)
at com.pixyfisocial.Login.getLoggedInUserInfoFromCache (Login.java:313)
at com.pixyfisocial.Login.startApp (Login.java:124)
at com.pixyfisocial.Login.onCreate (Login.java:98)
at android.app.Activity.performCreate (Activity.java:6303)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2376)
1条答案
按热度按时间wnavrhmk1#
对源代码的粗略检查表明
IllegalArgumentException
通常被扔进去ObjectInputStream
当序列化对象表示与读取类所期望的不匹配时。例如,您可能有不兼容的自定义项readObject
以及writeObject
方法。或者您可能对对象表示进行了二进制不兼容的更改,而没有更改硬编码serialVersionUID
数字或实现自定义方法来处理此问题2。你的指纹里会有更多线索。。。在源代码中
ObjectInputStream
.这个
ClassCastException
这可能是另一种表现。1-导致语义不兼容的变化是另一回事。他们不会导致
IllegalArgumentException
但是你还是应该做点什么。2-如果您想处理不兼容,那么您可能不想更改
serialVerionUID
. 如果您这样做了,那么您将需要对类加载和类的多个版本做一些“聪明的事情”。但另一方面,如果您的代码需要处理具有相同属性的多个表示形式serialVersionUID
,表示版本必须可以从表示本身推断出来。这需要计划。后续行动
我获取了你的stacktrace,并尝试将其与android源代码进行匹配https://android.googlesource.com
行号不完全匹配,但我认为问题发生在下面的方法中。特别是我标注的“这里”。根据javadoc for field.set:
如果指定的对象参数不是声明基础字段的类或接口的示例,则该方法将抛出illegalargumentexception。
如果基础字段是基元类型,则尝试展开转换以将新值转换为基元类型的值。如果此尝试失败,该方法将抛出illegalargumentexception。
如果在可能的展开之后,新值无法通过标识或加宽转换转换为基础字段的类型,则该方法将抛出illegalargumentexception。
这三件事中的一件正在发生。不可能说出哪一个。。。除非你提供一个完整的mcve(有人可以在android仿真器上运行!)。。。但这些迹象表明,您(不知何故)违反了序列化兼容性规则。
注意,由于行号不匹配,我不能确定您使用的android是否与下面的匹配。如果您想确定,您需要在git repo中搜索历史以找到匹配的版本。。。。或者查看设备的特定于供应商的源代码包/repo。