在进行Activity-->碎片1--> 碎片2如此包含关系的嵌套时遇到了以下问题:
本人写碎片时会习惯性在View进行实例化前,先去判断是否为null(如图1所示)。
这样是为了避免初始化碎片时,重复进行的view实例化占用资源。但如此操作会存在一些潜在问题(比如viewpage、或者碎片嵌套时。)
图1 碎片1的视图实例化
图2 碎片2的视图实例化
按照上面这种写法,在初次加载时不会有任何问题,但是在第二次加载时,便会出现报错
The specified child already has a parent. You must call removeView() on the child‘s parent first.
这是因为子视图(碎片2)和父视图(碎片1的容器)都因为这个null的判断而只会实例化一次,所以父与子都还是原来那个父与子,
而系统却不会如此绑定,所以会在二次加载时重新给子视图找一个parent,但绑定时却发现这个子视图已经有了parent,但系统又不能识别这次要绑定给子视图的parent其实已经绑定过了,所以就造成误会,导致报这个错。
解决方法有两种:
1.把子类view的判断“if(view==null)”去掉,保留父类的null判断,从而子变父不变
去掉判断后,每次加载时都会重新实例化一个新的子视图,新的child当然是没有parent的,所以系统想当然的就会把之前旧的parent分配给这个子视图当父容器,而旧的view安卓可能也会自动销毁释放(内存泄露问题在此先不做考虑),如此一来,等于第二次加载时系统把原来的子视图进行了重新的实例化后又绑定给了原来的父容器,父容器会在保留原来视图特性的情况下重新绘制新子视图的初始化。(比如子视图是一张地图的情况下,原先在父视图上绘制了一条路线,在二次加载时,地图实例虽然初始化了,但原来绘制的路线却会在父类视图保留下来。)
2.保留两个null判断的情况下,父与子还是原来的,为了避免系统“误会”,需要先让这对父与子脱离关系,解除掉绑定关系(父容器.removeAllView)。在父容器的类中,找到合适的生命周期位置,比如页面切走进入onPause时,加入如图所示备注掉的那行代码
图3 解除父容器linearLayout的所有视图绑定关系
如此一来,下次加载这个界面时,父与子已经断绝了关系,系统便可以再次对其进行绑定,以恢复原来的效果。
综上所述,以上两种方法均可以实现碎片嵌套时的重复加载问题。