文档章节

安卓java.lang.IllegalStateException: The specified child already has a parent.解决方案

htq
 htq
发布于 2016/07/26 09:40
字数 1287
阅读 115
收藏 0
点赞 0
评论 0

在使用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);
然后将多个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;
	}

	
	
}
其中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>
布局很简单,只是在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);
	}

可以看到第一种方案简单粗暴,但适用性不强,因为我们要添加的一个视图可能很复杂,而不是一个简单的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);     //这个地方出错,不能对其添加两次。
    }

解决方案也很简单,对于添加的第二个视图,重新用一个布局文件定义,然后通过inflater.inflate获取再动态添加。

本文转载自:http://blog.csdn.net/htq__/article/details/51290990

共有 人打赏支持
htq

htq

粉丝 19
博文 67
码字总数 1007
作品 3
武汉
Layout.addView时报错 java.lang.IllegalStateExcepti...

java.lang.IllegalStateException: The specified child already has a parent. 导致这个异常的原因是因为child View(就是addView方法的实参)已经在一个布局上add过了,如果这时候再去add...

hanQ ⋅ 2013/01/15 ⋅ 0

点击按钮弹出Dialog,点击第二次后出现 java.lang.IllegalStateException

不知是什么原因,为什么点击第一次可以正常弹出Dialog,点击第二次却出现错误? 错误显示: java.lang.IllegalStateException: The specified child already has a parent. You must call r...

剑麟 ⋅ 2013/04/07 ⋅ 4

android开发中出现的错误集(不断更新)

最后更新:2013-01-16 23.在使用AndroidHttpClient时有如下错误: 01-16 22:18:39.222: E/AndroidHttpClient(26745): java.lang.IllegalStateException: AndroidHttpClient created and nev......

李海珍 ⋅ 2012/03/17 ⋅ 6

错误集锦之一:This Activity already has an action bar supplied by the window decor.

异常信息: Caused by: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURESUPPORTACTION_BAR and s......

AwesomeQA ⋅ 2016/08/26 ⋅ 0

The specified child already has a parent. You must call removeView"

android动态加载fragment,会报上面那个错误,代码中没有动态addview的代码,半天没能找到问题。其实问题在onCreateView方法中inflater.inflate(R.layout.content_fragment, container); 函数...

open_虎皮猫 ⋅ 05/03 ⋅ 0

使用ViewPager报错java.lang.IllegalStateException: The specified child already has a parent. You must ...

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 不知道大家在使用ViewPager的时候有没有碰到过这个......

Magic_锋 ⋅ 2016/12/14 ⋅ 0

安卓问题集锦

问题1:The specified child already has a parent. You must call removeView() 原因:一个孩子只能有一个父亲,在调用的过程中同一个孩子出现了两个父亲。 解决方案:在添加视图之前断除孩...

dailei1021 ⋅ 2015/11/18 ⋅ 0

Android ViewPager之小圆点动态滑动

效果图 GIF.gif 第一步、布局 主界面布局,ViewPager+6个小圆点 MainActivity.xml 这里的可以通过drawable设置颜色样式 激活样式 未激活样式 第二步、ViewPager滑动展示的界面 view 第三步、继...

蛋蛋松 ⋅ 2017/11/06 ⋅ 0

开发原生安卓cordova插件(有原生界面)

上文开发的插件没有调用原生界面,本文介绍开发带有activity的插件 本文很多操作与上文重复,重复部分会省略 首先打开plug1,先开发插件的原生代码 在以下命名空间创建一个activity 名称为A...

canneljls ⋅ 04/21 ⋅ 0

react-native 启动页android

最近做一个项目,要用到启动页这个来解决启动白屏,就弄了一下,虽然网上一堆教程,但是还是踩了一堆坑,现在搞出来了,记录一下 下面是插件的GitHub地址 https://github.com/crazycodeboy/...

望-惘-尣 ⋅ 04/23 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 2分钟前 ⋅ 0

过滤器Filter和拦截器HandlerInterceptor

过滤器 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要...

hutaishi ⋅ 6分钟前 ⋅ 0

Redis入门详解(转)

Redis入门详解 Redis简介 Redis安装 Redis配置 Redis数据类型 Redis功能 持久化 主从复制 事务支持 发布订阅 管道 虚拟内存 Redis性能 Redis部署 Redis应用场景 Redis总结 Redis简介: Redi...

xiaoyaoyoufang ⋅ 19分钟前 ⋅ 0

说说javascript中的那些专业名词

DOM(Document Object Model) 文档对象模型 BOM(Browser Object Model) 浏览器对象模型 ECMA(European Computer Manufacturer's Association) 欧洲计算机制造商协会 W3C(World Wide Web Conso......

hang1989 ⋅ 38分钟前 ⋅ 0

Bootstrap Wizard 多步表单控件

废话 有一块需求是 有多步表单 点击下一步时触发验证一个范围内的表单,点击上一步或取消,清空表单并返回第一步,点击最后一步提交整个表单的 就找到了这个插件,本来自己写了一个原生的 fo...

无极之岚 ⋅ 54分钟前 ⋅ 0

如何利用Spring Cloud构建起自我修复型分布式系统

利用Netflix所打造的组件及各类大家熟知的工具,我们完全可以顺利应对由微服务以及分布式计算所带来的技术挑战。 在过去一年当中,微服务已经成为软件架构领域一个炙手可热的新名词,而且我们...

harries ⋅ 今天 ⋅ 0

临近实习前的感想

再过两星期就要开始新的一段实习了,想想去年的这个时候也在实习,心中不免思绪万千,也一直想写对2017做个总结,但一直迟迟没有下笔。 2017年的春节,我就开始准备开学后找份实习。那时候就...

无精疯 ⋅ 今天 ⋅ 0

Spring AOP(面向切面编程)

Spring AOP概念: Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。通常情况下,AOP把项目中需要在多处用到的功能,比如日志、安全和事物等集中到一个类中处理,而...

霍淇滨 ⋅ 今天 ⋅ 0

人工智能、机器学习、数据挖掘以及数据分析有什么联系?

人工智能是目前炙手可热的一个领域,所有的互联网公司以及各路大迦们纷纷表态人工智能将是下一个时代的革命性技术,可与互联网、移动互联网时代的变更相媲美;AlphaGo在围棋领域战胜人类最顶...

董黎明 ⋅ 今天 ⋅ 0

使用 vue-cli 搭建项目

vue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目,GitHub地址是:https://github.com/vuejs/vue-cli 一、 安装 node.js 首先需要安装node环境,可以直接到中...

初学者的优化 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部