【问题标题】:How to handle recycling in Expandablelistview with different child layouts?如何处理具有不同子布局的 Expandablelistview 中的回收?
【发布时间】:2025-11-29 07:10:01
【问题描述】:

众所周知,Android 的 listview 和 expandablelistview 回收了它的视图。更多信息:The nuance of android listview

我已经阅读了文章和信息,例如上面关于如何处理的链接,但他们只给出了列表视图的示例,而不是 Expandablelistview (而 getView 是 listview 中的唯一方法expandablelistview 有 getGroupView 和 getChildView)。

我的可扩展列表视图的子视图具有或需要具有不同的布局,因为这是实现应用程序输出所必需的。

现在,我的问题是如何正确处理可扩展列表视图的回收,该列表视图会在其子视图中膨胀不同的布局?比如把 viewHolderconvertView 放在我的 expandablelistview 的 getChildView 方法中的什么位置。

我按照site 中的以下代码实现了一个根据其位置膨胀不同布局的子级。

每当我点击另一个组时。前一个组的子级将其视图回收为其默认值,因此不会保留微调器和编辑文本值。我想可能是因为它再次膨胀了视图?

下面是我的 getChildView 方法:

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

            //layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
            //convertView = layoutInflater.inflate(R.layout.expandable_child_layout, parent, false);
        try{
            int itemType = getChildType(groupPosition, childPosition);

            switch(itemType){
            case 0:
                ViewHolder mainHolder = null;
                View v1 = null;
                if(v1 == null){

                    mainHolder = new ViewHolder();
                    v1 = View.inflate(context, R.layout.newtrip_main, null);
                    v1.setTag(mainHolder);

                    mainHolder.tripType = (Spinner) v1.findViewById(R.id.spinTripType);

                    /*TripTypeAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.triptypes)); //selected item will look like a spinner set from XML
                    TripTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    tripType.setAdapter(TripTypeAdapter);*/
                    mainHolder.tripType.setOnItemSelectedListener(this);

                }//else{
                    //mainHolder = (ViewHolder) v1.getTag();
                //}
                return v1;
                //break;
            case 1:

                ViewHolder  budgetHolder = null;
                View v2 = null;
                if(v2 == null){

                    budgetHolder = new ViewHolder();
                    v2 = View.inflate(context, R.layout.newtrip_budget, null);
                    v2.setTag(budgetHolder);

                    budgetHolder.budget = (Spinner) v2.findViewById(R.id.spinBudget);
                    budgetHolder.budgetAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.budgettype)); //selected item will look like a spinner set from XML
                    budgetHolder.budgetAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    budgetHolder.budget.setAdapter(budgetHolder.budgetAdapter);
                    budgetHolder.budget.setOnItemSelectedListener(this);

                }

                return v2;
                //break;
            case 2:

                ViewHolder  foodHolder= null;
                View v3 = null;
                if(v3 == null){
                    foodHolder = new ViewHolder();
                    v3 = View.inflate(context, R.layout.newtrip_food, null);
                    v3.setTag(foodHolder);
                }
                return v3;
                //break;
            case 3:

                ViewHolder  accomHolder= null;
                View v4 = null;
                if(v4 == null){
                    accomHolder = new ViewHolder();
                    v4 = View.inflate(context, R.layout.newtrip_accommodation, null);
                    v4.setTag(accomHolder);

                    accomHolder.accommodation = (Spinner) v4.findViewById(R.id.spinAccommodation);

                    accomHolder.accommodationAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.economicalAccomodation)); //selected item will look like a spinner set from XML
                    accomHolder.accommodationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    accomHolder.accommodation.setAdapter(accomHolder.accommodationAdapter);
                    //return convertView;
                }

                return v4;
                //break;

            }
        }catch(Exception e){
            Toast toast = Toast.makeText(context, e.toString(), Toast.LENGTH_LONG);
            toast.show();
        }
            convertView.invalidate();
            return convertView;
    }

这是 getGroupView 方法:

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {          


        convertView = View.inflate(context, R.layout.expandable_group_layout, null);
        TextView txtView = (TextView) convertView.findViewById(R.id.txt1);                 

        if(groupPosition == 0) {
          txtView.setText("   MAIN");
          txtView.setTextSize(15f);
          }
        if(groupPosition == 1) {
            txtView.setText("   BUDGET");
            txtView.setTextSize(15f);
          }
        if(groupPosition == 2) {
            txtView.setText("   FOOD");
            txtView.setTextSize(15f);
          }
        if(groupPosition == 3) {
            txtView.setText("   ACCOMMODATION");
            txtView.setTextSize(15f);
          }

        convertView.invalidate();
        return convertView;

    }

【问题讨论】:

    标签: android expandablelistview recycle


    【解决方案1】:

    我遇到了几乎同样的问题,我用这个解决了它:https://*.com/a/28550013/4342099

    尝试扩展BaseExpandableListAdapter并覆盖getChildTypeCount()getChildType()

    【讨论】:

      【解决方案2】:

      要控制可扩展列表视图中子列表的回收,请确保将更改的数据保存在哈希映射中,以便在向上滚动或不解析哈希映射数据时跟踪更改的数据列表,您可以看到结果。

      【讨论】:

        【解决方案3】:

        这完全一样。只需像对待普通getView 一样对待getChildView 方法。因此,对于您的情况,您需要执行以下操作:

        @Override
        public int getChildType(int groupPosition, int childPosition) {
            return groupPosition;
        }
        
        @Override
        public int getChildTypeCount() {
            return getGroupCount();
        }
        
        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
            switch (getChildType(groupPosition, childPosition) {
            case 1:
                ViewHolder vh = null;
                if (convertView == null) {
                    vh = new ViewHolder();
                    //Inflate your view
                    convertView.setTag(vh);
                } else {
                    vh = (ViewHolder) convertView.getTag();
                }
                //Load any data into view
                return convertView;
            case 2:
                //Repeat for all expected types
            }
        }
        

        【讨论】:

        • 我遵循了您的格式,但出现空指针异常。我将添加我在上面的问题中遇到的错误。
        • 你需要用ViewHolder设置convertView的setTag。更新代码
        • 你做了什么调试?你认为发生了什么?它在您的spinnerTripSelection 中崩溃,这似乎源自onItemSelected 侦听器。
        • 我修复了 onItemSelected 侦听器的问题,并且应用程序不会崩溃或产生错误,但我再次返回处理视图回收。每当我单击另一个组时。前一个组的子级将其视图回收为其默认值,因此不会保留微调器和编辑文本值。我想可能是因为它再次膨胀了视图?
        • 我必须对每个孩子或每个案例都有新的看法吗?我应该返回哪个视图?