项目里之前一直用序列化的方式部署一些缓存,今天在魅族MX5上发现反序列化缓存内容失效了,报错内容如下
java.io.EOFException
at java.io.DataInputStream.readByte(DataInputStream.java:77)
at java.io.ObjectInputStream.nextTC(ObjectInputStream.java:505)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:752)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1983)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1940)
at java.io.ObjectInputStream.readFieldValues(ObjectInputStream.java:1113)
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 java.util.ArrayList.readObject(ArrayList.java:661)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at java.io.ObjectInputStream.readObjectForClass(ObjectInputStream.java:1330)
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.imaginato.qravedconsumer.handler.bv.a(Unknown Source)
at com.imaginato.qravedconsumer.handler.bv.a(Unknown Source)
at com.imaginato.qravedconsumer.fragment.bl.a(Unknown Source)
at com.imaginato.qravedconsumer.fragment.bl.doInBackground(Unknown Source)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
返序列化的代码如下:
/** * 反序列化一个list * @param context * @param fileName * @param <T> * @return * @author Alex */ public <T> List<T> getArrayListFromDisk(Context context, String fileName) { if (context == null) return null; ObjectInputStream ois = null; File file = context.getCacheDir(); String path = file.getAbsolutePath().concat(fileName); File target = new File(path); if (!target.exists()) { Log.i("Alex","没有找到文件"+fileName); return null; } List<T> arrayList = null; synchronized (ArrayListLock) { try { ois = new ObjectInputStream(new FileInputStream(target)); arrayList = (ArrayList<T>) ois.readObject(); return arrayList; } catch (ClassNotFoundException e) { Log.i("Alex", "反序列失败", e); } catch (IOException e) { Log.i("Alex", "反序列失败2", e);//上面的报错是这里打出来的 } finally { if (ois == null) return null; try { ois.close(); } catch (IOException e) { Log.i("Alex", "反序列失败3", e); } return arrayList; } } }
使用任务管理器强制关闭app的时候经常会出现这种情况
后来发现可能是由于序列化文件损坏引起的,如果在一个线程里对这个文件执行写入操作,而线程没有正常的结束而被强行终止了,可能会导致当前操作的文件损坏,所以导致问题的代码如下
@Override public void onDestroy() { Log.i("Alex", "fragment2的onStop执行"); if (aveArrayListToDisk(getActivity(), CARDS_LIST, "/homeCards.tmp")) JLogUtils.i("Alex", "序列化卡片到硬盘成功"); else Log.i("Alex", "序列化卡片失败"); super.onDestroy(); Log.i("Alex", "fragment的onDestroy执行了!!!"); }
这个bug得到的教训是,耗时操作不要放在onDestroy()里,onDestroy()可能不会被执行或者还没等执行完app的进程就被终止了,这对IO操作是致命的。