大概就是 RecyclerView 里面有个 inner class 是 Observer 用来观察 Adapter 的数据变化。因为用的是非静态内部类,这个 Observer 和这个 RecyclerView 就会有互相引用。这个不是问题的关键因为一旦 RecyclerView 没有 Activity 或者 Fragment 引用了就会一起回收。
问题是,这个 Adapter 里面的 Observable 也是个内部类,而 Observable 会把传进来的 Observer 存起来。这样的话,如果我 Adapter 放在一个 Fragment 里面,然后这个 Fragment 放到 Backstack 里面去的时候 Adapter 本身应该是不会销毁的( onDestoy 没有调用),这样的话 RecyclerView 也不会被回收(尽管 onDestroyView 调用了)。
我目前是用了 RecyclerView.setAdapter(null)来解决这个问题,我想知道是不是我打开方式不对?
又研究了一阵,看了一些开源项目的代码还有Android的一些源码,我发现这个问题其实是有手动解决的办法。
可以先看看这个问题http://stackoverflow.com/questions/26369905/activitys-ondestroy-fragments-ondestroyview-set-null-practices
对于Activity来说,OnDestory就真Destory了,不会有这个问题。但是对于Fragment来说,平时我们把它放到Backstack里面的时候,只有View是销毁的,非View的部分是会保留的。这就造成了Adapter不会被自动释放,从而导致RecyclerView不被释放。
解决方法从两个思路入手:
-
在OnDestoryView里,不仅把RecyclerView设为null,同时手动把Adapter设为null,这样就强制断开了Fragment对Adapter的引用。这个方法的缺点是你需要在OnCreateView里面重新初始化Adapter(以前我们可以在OnCreate里面初始化)。其实这样对性能影响并不会很大,因为Adapter一般比较轻量。这种思路可以在这里看到(链接过去的是一个比较出名的Android库)。
-
在Fragment里面不保留Adapter的引用。也就是说Adapter是个本地变量,直接创建好了马上传给RecyclerView。之后如果要用就通过RecyclerView去拿就好了。这种方法其实和上面那种很像,只是不需要手动管理引用了。同样是因为没有引用,所以每次创建RecyclerView的时候也要重新创建Adapter。这种思路在Android自己实现的PreferenceFragmentCompat里面可以看到。
以上两种方法都需要重新创建Adapter,但是都能解决内存溢出问题。想到之前看过的一篇文章说Fragment是Android里面最蛋疼的东西。。。有点后悔用 One Activity + Multiple Fragments这种架构了。。。