安卓java.lang.IllegalStateException: The specified child already has a parent.解决方案
在使用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获取再动态添加。
安卓java.lang.IllegalStateException: The specified child already has a parent.解决方案的更多相关文章
- java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
在ViewPager中,用Fragment显示页面时,报错: java.lang.IllegalStateException: The specified child already has a pa ...
- 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 removeVi ...
- 关于viewpager 里嵌套 listview 同时实现翻页功能的“java.lang.IllegalStateException: The specified child..."异常处理
这几天做项目用到了ViewPager,因为它可以实现左右划动多个页面的效果,然后 再每个页面里使用ListView,运行时总是出现”PagerAdapter java.lang.IllegalStat ...
- SpringMVC Tomcat 启动时报错:java.lang.IllegalStateException: Error starting child
大概原因如下: 1.Controller里RequestMapping("/test")前面没有"/"; 2.jar包冲突,比如我的将数据库连接版本由5.1.6 ...
- 异常java.lang.IllegalStateException的解决
在初始化viewPagerAdapter时,显示异常.从网上找了找有两类这样的问题,一种是说给一个视图设置了两个父类,如: TextView tv = new TextView();layout.ad ...
- Android IllegalStateException: The specified child already has a parent问题解决办法
最近遇到一个很让人头疼的问题,使用viewpager动态添加页面或者删除页面时出现了问题(java.lang.IllegalStateException: The specified child al ...
- Tomcat部署项目时出错java.lang.IllegalStateException: ContainerBase.addChild: start:org.apache.catalina.Life
Tomcat部署项目时出错java.lang.IllegalStateException: ContainerBase.addChild: start:org.apache.catalina.Life ...
- myeclipse 无法启动 java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).
把myeclipse10 按照目录完整拷贝到了另外一台电脑, 另外的目录 原安装目录 D\:\soft\i\myeclipse10 新安装目录 E\:\soft\myeclipse10 双击启动失败, ...
- java.lang.IllegalStateException:Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxx...}: java.lang.IllegalSta ...
随机推荐
- Windows 2008 R2_NLB网络负载均衡(图文详解)(转)
目录 前言 软件环境 DNS域名服务器 DNS服务器原理 DNS域名空间 DNS区域 DNS服务器的类别 DNS查询模式 缓存文件 配置DNS服务器 DNS服务的应用 新建子域 在DNS正向解析中新建 ...
- Java访问修饰符及其访问控制
java中的访问修饰符,可以看成是人的秘密分享级别.private 个人秘密 ,protected 家族秘密,default(不写修饰符)社区(邻居)秘密(在一个包下的能访问),public 社会秘密 ...
- ubuntu远程桌面连接命令rdesktop连接windows远程桌面详解
sudo apt-get install rdesktoprdesktop 124.42.120.174:1433 呵呵,连接成功了. -f 全屏-a 16位色默认端口是3389(linux 22 s ...
- Wcf host
Uri baseAddress = new Uri(uri);//var binding = new WebHttpBinding(WebHttpSecurityMode.None); var bas ...
- 代码之间-论文修改助手v1.0版本发布
论文查重,是每个毕业生都要面临的一个令人头疼的问题,如果写论文不认真,很可能导致查重红一大片. 之前有帮助一些朋友修改论文降低重复率,做了一些工作后发现,国内的查重机构,如知网.维普等,大多数是基于关 ...
- R语言使用 multicore 包进行并行计算
R语言是单线程的,如果数据量比较大的情况下最好用并行计算来处理数据,这样会获得运行速度倍数的提升.这里介绍一个基于Unix系统的并行程序包:multicore. 我们用三种不同的方式来进行一个简单的数 ...
- CF | Alyona and Mex
Someone gave Alyona an array containing n positive integers a1, a2, ..., an. In one operation, Alyon ...
- ACM Robot Motion
机器人已被编程为按照其指令中的路径进行操作.机器人要移动的下一个方向的指令放在网格中.可能的指令是 N north (up the page) S south (down the page) E ...
- PHP 完整表单实例
PHP - 在表单中确保输入值 在用户点击提交按钮后,为确保字段值是否输入正确,我们在HTML的input元素中插添加PHP脚本, 各字段名为: name, email, 和 website. 在评论 ...
- Docker服务端防护
运行一个容器或应用程序的核心是通过 Docker 服务端.Docker 服务的运行目前需要 root 权限,因此其安全性十分关键. 首先,确保只有可信的用户才可以访问 Docker 服务.Docker ...