Android 反序列化异常EOFException的解决

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvshaorong/article/details/51673721

项目里之前一直用序列化的方式部署一些缓存,今天在魅族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执行了!!!");
    }

这是Fragment的onDestroy()方法,其中“fragment的onDestroy执行了!!!”不会被打印出来.解决方法很简单,把这块IO代码写到onStop()里去就可以了。

这个bug得到的教训是,耗时操作不要放在onDestroy()里,onDestroy()可能不会被执行或者还没等执行完app的进程就被终止了,这对IO操作是致命的。

阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页