java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
是什么意思?往下看↓:
<LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@mipmap/circle_bg"> <android.support.v4.view.ViewPager android:id="@+id/viewpager_firstpage" android:layout_width="match_parent" android:layout_height="200dp" android:paddingLeft="30dp" android:paddingRight="30dp" > </android.support.v4.view.ViewPager>`
出错的代码主要是在ViewPager的适配器类的instantiateItem方法中,因为在该方法中我们通常会动态的添加视图。在自己的项目的主界面中定义了一个ViewPager用来循环显示多个imageView,而在主界面中imageView是通过container.addView(imageView)来动态获取的,我们定义的viewPager在其外层有一个线性布局。错误分析:因为ViewPager的视图的显示是在PagerAdapter中通过instantiateItem方法来动态添加的,通常我们在该方法中会调用container.addView(viewList.get(position));来添加一个视图,即调用ViewPager的addView来动态添加控件,但是可以看到在我们的R.layout.viewpager的XML文件中ViewPager的外部是LinearLayout布局控件,即此时ViewPager的父控件为LinearLayout,这样就相当于把一个已存在父控件的子控件动态的添加到一个ViewPager容器中,这是不被允许的,因为一个子控件只允许存在一个父容器控件,因此会报错。解决办法:去除R.layout.viewpager的XML文件中ViewPager的外部的LinearLayout布局控件,这样ViewPager就不存在父容器控件。但是通常我们会在viewpager的外部会设置一个父布局,以满足我们复杂的界面要求。所以解决办法一并不是完美的。在PagerAdapter中通过instantiateItem方法中动态添加视图前做一个简单的判断,判断待添加的视图是否已存在父控件,若存在则调用removeView()去除。代码如下:
public Object instantiateItem(ViewGroup container, int position) { int newPosition = position % imageViewList.size(); ImageView imageView = imageViewList.get(newPosition); ViewGroup parent = (ViewGroup) imageView.getParent(); if (parent != null) { parent.removeView(imageViewList.get(newPosition)); } // a. 把View对象添加到container中 container.addView(imageView); // b. 把View对象返回给框架, 适配器 return imageView; // 必须重写, 否则报异常 }`想到既然出现的问题是由于其本来是3个轮播图却加载了5次,这就导致第二次加载重复的轮播图,也就是第四和第五次加载的是重复的视图,所以这个也是导致父控件已经是container了,再次加载当然也会报错父布局已经存在了,所以我又去翻看源码,有没有什么方法可以将这个父布局直接给干掉,突然我好像是发现了什么:看看这个方法↓:
public Object instantiateItem(ViewGroup container, int position) { return instantiateItem((View) container, position); }这个方法调用的是后面这个方法return instantiateItem((View) container, position),我好像知道了点什么,看这两个方法的参数,一个是ViewGroup一个是View,那么我们直接重写后面这个方法不就好了吗,就不会出现父布局已经存在的情况,因为这是一个view不能包含子控件的,所以我就可以直接将我的图片资源ID在这里加载,不用在activity中添加了,想到这里我就开始实现它了:
public Object instantiateItem(ViewGroup container, int position) { int newPosition = position % imageViewList.size(); ImageView imageView = imageViewList.get(newPosition); if (newPosition==0) { container.setBackgroundResource(R.mipmap.aaa); } if (newPosition==1) { container.setBackgroundResource(R.mipmap.bbb); } if (newPosition==2) { container.setBackgroundResource(R.mipmap.ccc); } // b. 把View对象返回给框架, 适配器 return imageView; // 必须重写, 否则报异常 }