java.lang.IllegalStateException: The specified child already has a parent
来源:互联网 发布:农村淘宝面试题目 编辑:程序博客网 时间:2024/06/03 14:53
在使用ViewPager的时候遇到一个错误java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child’s parent first.。经过多次调试及网上查找相关资料,终于弄明白是咋回事,现记录如下:
首先跟大家讲解一下为何会出现该错误,然后再提供自己的错误代码分析错误原因及解决方案。
一为何会报java.lang.IllegalStateException: The specified child already has a parent.错误
根据The specified child already has a parent. You must call removeView() on the child’s parent first.的字面意思是一个子View已经存在一个父View,你必须先调用该子视图的父视图的 removeView() 方法,这种情况通常出现在动态添加视图的情况下,出现这种错误的原因是一个子控件只允许存在一个父控件,而很多时候在动态添加视图的时候,我们不知道该子视图是否已存在父视图,当已存在的时候就会报错。
二错误代码分析错误及解决方案:
出错的代码主要是在ViewPager的适配器类的instantiateItem方法中,因为在该方法中我们通常会动态的添加视图。在自己的项目的主界面中定义了一个ViewPager用来循环显示多个GridView,而在主界面中GridView是通过LayoutInflater来动态获取的,代码如下:
- LayoutInflater inflater=getActivity().getLayoutInflater();
- View view=inflater.inflate(R.layout.viewpager,null);
- campanyGridView=(GridView) view.findViewById(R.id.campany_gridview_1);
LayoutInflater inflater=getActivity().getLayoutInflater(); View view=inflater.inflate(R.layout.viewpager,null); campanyGridView=(GridView) view.findViewById(R.id.campany_gridview_1);然后将多个campanyGridView添加到List集合中,然后将该ArrayList集合对象作为参数传递给ViewPager对应的Adapter,代码如下:
- public class ViewPaperAdapter extends PagerAdapter {
- private ArrayList<View> viewList;
- public ViewPaperAdapter(ArrayList<View> viewList) {
- // TODO Auto-generated constructor stub
- this.viewList=viewList;
- }
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- // TODO Auto-generated method stub
- //super.destroyItem(container, position, object);
- container.removeView(viewList.get(position));
- }
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return viewList.size();
- }
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- // TODO Auto-generated method stub
- return arg0==arg1;
- }
- }
public class ViewPaperAdapter extends PagerAdapter { private ArrayList<View> viewList; public ViewPaperAdapter(ArrayList<View> viewList) { // TODO Auto-generated constructor stub this.viewList=viewList; } @Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub //super.destroyItem(container, position, object); container.removeView(viewList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(viewList.get(position)); return viewList.get(position); } @Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0==arg1; }}其中PagerAdapter中的instantiateItem方法是用来显示我们添加的视图控件的,其中视图对应的R.layout.viewpager的XML文件如下:
- <?xml version=“1.0” encoding=“utf-8”?>
- <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
- android:layout_width=”match_parent”
- android:layout_height=”match_parent”
- android:orientation=”vertical” >
- <GridView
- android:id=”@+id/campany_gridview_1”
- android:layout_width=”match_parent”
- android:layout_height=”wrap_content”
- android:horizontalSpacing=”10dp”
- android:verticalSpacing=”10dp”
- android:numColumns=”3”
- ></GridView>
- </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <GridView android:id="@+id/campany_gridview_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:horizontalSpacing="10dp" android:verticalSpacing="10dp" android:numColumns="3" ></GridView></LinearLayout>布局很简单,只是在LinearLayout中放了一个GridView控件而已。但是当点击自己项目APP的底部导航按钮(界面类似QQ)来切换界面时报错,即java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child’s parent first.。通过我们上述讲解大家应该能够明白为何出错。
错误分析:因为ViewPager的视图的显示是在PagerAdapter中通过instantiateItem方法来动态添加的,通常我们在该方法中会调用container.addView(viewList.get(position));来添加一个视图,即调用ViewGroup的addView来动态添加控件,但是可以看到在我们的R.layout.viewpager的XML文件中GridView的外部是LinearLayout布局控件,即此时GridView的父控件为LinearLayout,这样就相当于把一个以存在父控件的子控件动态的添加到一个ViewGroup容器中,这是不被允许的,因为一个子控件只允许存在一个父容器控件,因此会报错。
解决方案:通过上述的分析可以很容易找到解决方案:
1去除R.layout.viewpager的XML文件中GridView的外部的LinearLayout布局控件,这样GridView就不存在父容器控件。
2在在PagerAdapter中通过instantiateItem方法中动态添加视图前做一个简单的判断,判断待添加的视图是否已存在父控件,若存在则调用removeAllViews()去除之。代码如下:
- public Object instantiateItem(ViewGroup container, int position) {
- // TODO Auto-generated method stub
- View v=viewList.get(position);
- ViewGroup parent = (ViewGroup) v.getParent();
- //Log.i(“ViewPaperAdapter”, parent.toString());
- if (parent != null) {
- parent.removeAllViews();
- }
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub View v=viewList.get(position); ViewGroup parent = (ViewGroup) v.getParent(); //Log.i("ViewPaperAdapter", parent.toString()); if (parent != null) { parent.removeAllViews(); } container.addView(viewList.get(position)); return viewList.get(position); }
可以看到第一种方案简单粗暴,但适用性不强,因为我们要添加的一个视图可能很复杂,而不是一个简单的GridView,那么我们必须使用类似LinearLayout的基本布局控件来控制我们的视图,因此第二种方案很显然适用此种情况。
三总结:
ViewGroup的addView()方法不能添加一个已存在父控件的视图,因此在使用类似ViewPager的控件动态添加视图时,要在addView前先判断再添加,上述案例可以扩展为不能使用addView()对同一个控件动态添加两次,因为第一个添加时已表示该子控件已存在父容器控件,第二次添加时尽管其父容器控件是同一个控件,但是相当于该子视图已存在父容器控件,因此仍会报错,如下代码是错误的:
- private void initView() {
- LinearLayout viewGroup = (LinearLayout) findViewById(R.id.main_activity_linearlayout);
- LayoutInflater inflater = LayoutInflater.from(this);
- View textView = inflater.inflate(R.layout.test, null);
- viewGroup.addView(textView);
- viewGroup.addView(textView); //这个地方出错,不能对其添加两次。
- }
private void initView() { LinearLayout viewGroup = (LinearLayout) findViewById(R.id.main_activity_linearlayout); LayoutInflater inflater = LayoutInflater.from(this); View textView = inflater.inflate(R.layout.test, null); viewGroup.addView(textView); viewGroup.addView(textView); //这个地方出错,不能对其添加两次。 }
解决方案也很简单,对于添加的第二个视图,重新用一个布局文件定义,然后通过inflater.inflate获取再动态添加。
- java.lang.IllegalStateException: The specified child already has a parent.
- java.lang.IllegalStateException:The specified child already has a parent.
- java.lang.IllegalStateException: The specified child already has a parent
- java.lang.IllegalStateException The specified child already has a parent. You must call removeView()
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView
- Android异常分析之 java.lang.IllegalStateException:the specified child already has a parent.
- java.lang.IllegalStateException The specified child already has a parent. You must call removeView()
- Caused by: java.lang.IllegalStateException: The specified child already has a parent. You
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- Android—java.lang.IllegalStateException: The specified child already has a parent. You must call rem
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- Android | java.lang.IllegalStateException: The specified child already has a parent. 解决方案
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView(
- viewpager的使用bug:java.lang.IllegalStateException: The specified child already has a parent.
- hashcode()与equals()
- Log4Qt 使用笔记(一)
- 7-1 是否同一棵二叉搜索树(25 分)
- Shader内置函数
- Java的类、方法、属性(多态,继承,封装)
- java.lang.IllegalStateException: The specified child already has a parent
- JSONP原理探究
- windows&linux设置系统自动退出时间(无操作超时设置)
- RMQ静态区间最值查询
- C++中的常引用
- (转)正则表达式
- 第二章—C++简单程序设计(一)
- for循环和foreach循环的区别?
- Log4Qt 使用笔记(二)