java.lang.IllegalStateException:指定的子级已有父级。如何确保删除所有视图?

时间:2014-06-15 22:45:56

标签: android view viewgroup removeall

嗨,有很多相关的话题都是关于这个问题,我看了一下。我已经按照这些相关的答案,我使用了这些建议,但我仍然在logcat上收到以下错误:

06-16 02:54:22.333: W/System.err(20722): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

我有一个从LinearLayout类扩展的PitchView。 ArrayList<PlayerView> playerList;包含我的玩家列表,setupTeamView()方法负责绘制类。

用户可以更换玩家。所以我将chanes添加到数组列表(playerList),然后立即调用setupTeamView()来重绘类。第一次运行应用程序时没有问题但是当我根据新数据调用setupTeamView()方法重绘屏幕时,应用程序崩溃并且logcat显示标记的行。我有一个clearTeamView()方法负责清除此类的容器。虽然它已经运行但似乎没有删除它的孩子(llContainer方法中setupTeamView())。

我花了大约10个小时来解决这个问题但是没有成功。如果有人告诉我我的问题是什么,我将非常感激。感谢。

public class PitchView extends LinearLayout {

   private ArrayList<PlayerView> playerList;

   public void clearTeamView() {
        final LinearLayout parentLayout = (LinearLayout) this.findViewById(R.id.team_pitch_view);
        parentLayout.removeAllViews();
    }

    public void setupTeamView() {
        if(playerList == null)
            return;

        // remove all views
        clearTeamView();

        // to count from 1-11 (Number of Players)
        int pointer = 1;

        // Get formation
        ArrayList<Integer> formationArr = Formation.getFormationAsArray(formation);

        // Container to hold other views inside
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 1f);
        LinearLayout llContainer = new LinearLayout(getContext());
        llContainer.setOrientation(LinearLayout.VERTICAL);
        this.addView(llContainer, params);

        // -1.... This is to cover the goalie case, who is always present, and always on his own
        for(int i = -1; i < formationArr.size(); i++) {

            if(i == -1) {
                PlayerView goaller = playerList.get(0);
                goaller.switchStatistics(rightStatsOn);
                goaller.setOnPlayerClickedListener(listener);
                goaller.setGravity(Gravity.CENTER);

                LinearLayout goalieLayout = new LinearLayout(getContext());
                goalieLayout.setOrientation(LinearLayout.HORIZONTAL);
                goalieLayout.addView(goaller, params); <<<<<<<<<<<<<<<<<<<<<< ERROR

                llContainer.addView(goalieLayout);
            } else {
                LinearLayout teamMemberLayout = new LinearLayout(getContext());
                teamMemberLayout.setOrientation(LinearLayout.HORIZONTAL);

                for (int j = 0; j < formationArr.get(i); j++) {
                    PlayerView player = playerList.get(pointer++);
                    player.switchStatistics(rightStatsOn);
                    player.setOnPlayerClickedListener(listener);
                    player.setGravity(Gravity.CENTER);

                    teamMemberLayout.addView(player, params);
                }

                llContainer.addView(teamMemberLayout);
            }
        }
    }

...
}  

====== UPDATE ==

感谢CommonsWare的建议,我得到了很好的想法但不幸的是,我有同样的问题。我改变了

public void clearTeamView() {
            final LinearLayout parentLayout = (LinearLayout) this.findViewById(R.id.team_pitch_view);
            parentLayout.removeAllViews();
        }

public void clearTeamView() {
            this.removeAllViews();
        }

但我有同样的问题。我还尝试在setupViews中将llContainer添加到parentLayout但不幸的是,结果相同:(

所以,我决定重构我的viewGroup。但我仍然得到相同的结果:((((似乎它并不像我一样

任何方式,而不是动态创建所有内容,我决定为我的视图组创建一个布局,如下所示:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/bg_play_ground"
        android:id="@+id/ivPlayGround"
        android:contentDescription="@string/general_content_description"
        android:alpha="0.2"
        android:scaleType="fitXY"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="7dp"
        android:id="@+id/llContainer">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="horizontal"
            android:gravity="center"
            android:id="@+id/llGoalieLayout">

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="horizontal"
            android:gravity="center"
            android:id="@+id/llDefLayout">

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="horizontal"
            android:gravity="center"
            android:id="@+id/llMedLayout">

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="horizontal"
            android:gravity="center"
            android:id="@+id/llFwdLayout">

        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

并以此形式更改了类:

public class PitchView extends RelativeLayout {

    private static final String TAG = "PitchView";

    private Context mContext;
    public Formation.FORMATION formation;

    private ArrayList<PlayerView> playerList;

    private LinearLayout llContainer;
    private LinearLayout llGoalieLayout;
    private LinearLayout llDefLayout;
    private LinearLayout llMedLayout;
    private LinearLayout llFwdLayout;

    private void init() {
        LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        RelativeLayout view = (RelativeLayout) mInflater.inflate(R.layout.widget_pinch_view, null);
        addView(view);

        llContainer = (LinearLayout) view.findViewById(R.id.llContainer);
        llGoalieLayout = (LinearLayout) view.findViewById(R.id.llGoalieLayout);
        llDefLayout = (LinearLayout) view.findViewById(R.id.llDefLayout);
        llMedLayout = (LinearLayout) view.findViewById(R.id.llMedLayout);
        llFwdLayout = (LinearLayout) view.findViewById(R.id.llFwdLayout);

        this.formation = Formation.FORMATION.four_four_two;

        setupTeamView();
    }

    public void clearTeamView() {
        llGoalieLayout.removeAllViews();
        llDefLayout.removeAllViews();
        llMedLayout.removeAllViews();
        llFwdLayout.removeAllViews();

        Log.e(TAG, "goalie child count: " + llGoalieLayout.getChildCount());
        Log.e(TAG, "DEF child count: " + llDefLayout.getChildCount());
        Log.e(TAG, "MED child count: " + llMedLayout.getChildCount());
        Log.e(TAG, "FWD child count: " + llFwdLayout.getChildCount());
    }

    public void setupTeamView() {
        if(playerList == null)
            return;

        // remove all views)
        clearTeamView();

        // Get formation
        ArrayList<Integer> formationArr = Formation.getFormationAsArray(formation);

        // to count from 0-10 (Number of Players)
        int pointer = 0;

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 1f);

        // 1. This is to cover the goalie case, who is always present, and always on his own
        PlayerView goaller = playerList.get(pointer);
        goaller.switchStatistics(rightStatsOn);
        goaller.setOnPlayerClickedListener(listener);
        goaller.setGravity(Gravity.CENTER);
        llGoalieLayout.addView(goaller, params);

        // 2. This is to cover the defender cases
        for(int i=0; i<formationArr.get(0); i++) {
            PlayerView defender = playerList.get(++pointer);
            defender.switchStatistics(rightStatsOn);
            defender.setOnPlayerClickedListener(listener);
            defender.setGravity(Gravity.CENTER);
            llDefLayout.addView(defender, params); <<<<<<<<<<<<<< ERROR
        }

        // 3. This is to cover the midfielder cases
        for(int i=0; i<formationArr.get(1); i++) {
            PlayerView midfielder = playerList.get(++pointer);
            midfielder.switchStatistics(rightStatsOn);
            midfielder.setOnPlayerClickedListener(listener);
            midfielder.setGravity(Gravity.CENTER);
            llMedLayout.addView(midfielder, params);
        }

        // 4. This is to cover the attacker cases
        for(int i=0; i<formationArr.get(2); i++) {
            PlayerView attacker = playerList.get(++pointer);
            attacker.switchStatistics(rightStatsOn);
            attacker.setOnPlayerClickedListener(listener);
            attacker.setGravity(Gravity.CENTER);
            llFwdLayout.addView(attacker, params);
        }

        Log.e(TAG, "goalie child count: " + llGoalieLayout.getChildCount());
        Log.e(TAG, "DEF child count: " + llDefLayout.getChildCount());
        Log.e(TAG, "MED child count: " + llMedLayout.getChildCount());
        Log.e(TAG, "FWD child count: " + llFwdLayout.getChildCount());
    }
.
.
.
}

与上次相同,应用程序在第一次尝试时工作正常,但在我想要重新组织玩家时会崩溃。

这是登录首次运行的输出:

06-16 17:47:33.326: E/PitchView(24305): goalie child count: 0
06-16 17:47:33.326: E/PitchView(24305): DEF child count: 0
06-16 17:47:33.326: E/PitchView(24305): MED child count: 0
06-16 17:47:33.326: E/PitchView(24305): FWD child count: 0
06-16 17:47:33.346: E/PitchView(24305): goalie child count: 1
06-16 17:47:33.346: E/PitchView(24305): DEF child count: 4
06-16 17:47:33.346: E/PitchView(24305): MED child count: 4
06-16 17:47:33.346: E/PitchView(24305): FWD child count: 2

替换后(形成相同但播放器的新对象添加到playerList并且setupTeamView想要重绘缩放区域)

06-16 17:50:35.331: E/PitchView(24305): goalie child count: 0
06-16 17:50:35.331: E/PitchView(24305): DEF child count: 0
06-16 17:50:35.331: E/PitchView(24305): MED child count: 0
06-16 17:50:35.331: E/PitchView(24305): FWD child count: 0
06-16 17:52:13.321: E/AndroidRuntime(25088): FATAL EXCEPTION: main
06-16 17:52:13.321: E/AndroidRuntime(25088): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
06-16 17:52:13.321: E/AndroidRuntime(25088):    at com.allstarxi.view.PitchView.setupTeamView(PitchView.java:169)

正如您所看到的,所有观看次数都已删除,但我仍然会得到&#34; 您必须首先在孩子的父母身上调用removeView()。&#34 ;

3 个答案:

答案 0 :(得分:0)

您要移除parentLayout的所有观看次数。您没有将llContainer添加到parentLayout。您已将llContainer添加到this。由于parentLayoutthis的孩子(因为您是通过findViewById()找到的),llContainer无法成为parentLayout的孩子,所以删除parentLayout的子女不会影响llContainer

llContainer需要parentLayout的孩子,或者您需要删除this的所有观看,或者您需要从llContainer删除this除了你当前的代码。

答案 1 :(得分:0)

如果您的所有孩子都有 llContainer 作为父级,那么为什么要从 R.id.team_pitch_view 中删除所有孩子?

下一个版本:

for(PlayerView player : playerList){
((LinearLayout)player.getParent()).removeView(player);
}

答案 2 :(得分:0)

您的布局只支持一个子视图,您必须从中删除所有视图才能添加另一个视图。