ExpandableListAdapter删除组问题

时间:2018-11-03 06:46:00

标签: android expandablelistview expandablelistadapter

我在从ExpandableListView中删除组时遇到了很大的问题。即使在Google大量尝试了很多教程和示例之后,我也无法解决它。

尽管我有很多编程经验,但我对Android编程还是比较了解的。因此,我相信源代码中还有很多事情还没有做好。但是到目前为止,从列表中删除组后,我想以错误的观点关注问题。

下面是一些截图,以便对问题进行很好的概述

应用程序启动

The MainActivity

点击按钮列出所有预算后列出

The not expanded groups on BudgetListActivity

所有网上论坛扩展

Groups expandet

在删除最后一组的最后一个孩子之前

before deleting last child of group 2

其余组向孩子展示两次

remaining group show children twice

最后一次带两个孩子

last group has two children

删除最后一组的最后一个孩子之前

before delteing last child of group 2

删除最后一组的最后一个孩子后的正确结果

result after deleting last child of group 2

我希望问题能解决。如果最后一组只有一个孩子并且被删除,则整个组将被应用程序删除-但是第一组的孩子会出现两次。

在调试会话期间,我检查了数据背后的所有资源,它们都正常。如果我返回MainActivity并再次启动列表,则视图完全正确。因此,删除整个组后一定是填充不正确的问题。

如您所见,如果我仅从具有两个孩子的最后一个小组中删除最后一个孩子,则整个列表的填充是正确的。

以下是有关该应用程序的更多信息:

  • 我使用一个房间数据库,其中有两个保存数据的表。

    一个表格包含名称和ID的类别,另一个表格用于类别ID为外键的单个预算记录 project database

在BudgetListActivity的onCreate中,我创建了两个DAO的budgetDAO和categoryDAO以获取数据并填充列表allBudgetsList和所有CatList。 利用这些信息,我创建了一个新的数组,列出了具有视图所需结构的allGroups  -分类作为标题  -由于有外键,预算还是孩子

(这里只有一句话: 同时,我已经尝试将哈希映射用于提供给ExpandableListAdapter的数据-但结果是相同的错误视图填充!)

有一个contentView“ budget_expandable_list”设置为ExpandableListAdapter。适配器应使用ArrayList“ allGroups”中的数据填充此列表的组和子级。

这是应用程序的结构 app structure

可能有一些实际未使用的资源。

我现在将为importand类提供源代码

BudgetListActivity:

package com.wbapps.WBEasyBudgetManagement;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.app.AppCompatActivity;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BudgetListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
    CoordinatorLayout coordinatorLayout;
    private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

    //wb, 23Oct2018: now using an array list for the expandable list adapter
    ArrayList<Group> allGroups = new ArrayList();

    private ArrayAdapter adapter;
    private final int REQUEST_CODE_EDIT = 1;

    private BudgetDAO budgetDAO;
    private CategoryDAO categoryDAO;

    List<Budget> allBudgetsList;
    List<Category> allCatsList;

    ExpandableListView expListView;
    List<String> expListViewTitle;
    ExpandableListAdapter expAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.budget_expandable_list);

        if (allGroups.size() > 0 ) {allGroups.clear();}
        //get instances for DAO's of db from MainActivity
        budgetDAO = MainActivity.getBudgetDAO();
        categoryDAO = MainActivity.getCategoryDAO();

        //the list for budgets and categories
        allBudgetsList = budgetDAO.getBudgets();
        allCatsList = categoryDAO.getCategories();

        //temporary Group-Object for the ArrayList allGroups
        Group tmpGroup;
        double sumExpenses = 0;
        //Start with reading all categories
        for (int i=0;i<allCatsList.size(); i++) {
            String tmpCat = allCatsList.get(i).getCategory();
            tmpGroup = new Group(tmpCat);
            sumExpenses = 0.0;
            //now read all budgets for the current category and fill the rest of the temporary Group-Object
            for (int j=0;j<allBudgetsList.size();j++){
                if (allBudgetsList.get(j).getCategoryId() == allCatsList.get(i).getId()){
                    //tmpGroup.budgetId = allBudgetsList.get(j).getId();
                    tmpGroup.catId = allBudgetsList.get(j).getCategoryId();

                    tmpGroup.children.add(Arrays.asList
                            (
                                    " Date: " + sdf.format(allBudgetsList.get(j).getDateTime())
                                            + " - Expenses: " + Double.toString(allBudgetsList.get(j).getExpenses()),
                                    Long.toString(allBudgetsList.get(j).getId())
                            )
                    );

                    sumExpenses = sumExpenses + allBudgetsList.get(j).getExpenses();
                    tmpGroup.sumExpenses = sumExpenses;
                }
            }
            //if at least one children for the current category was found
            // =>> write all the group information the the array list
            if (tmpGroup.children.size() > 0 ) {allGroups.add(tmpGroup);}
        }
        expListView = (ExpandableListView) findViewById(R.id.expandableList);
        expAdapter = new ExpandableListAdapter(this, allGroups);
        expListView.setAdapter(expAdapter);
        expListView.setOnItemClickListener(this);
        registerForContextMenu(expListView);
    }

    @Override
    public void onCreateContextMenu(ContextMenu contMenu, View v,
                                    ContextMenu.ContextMenuInfo contextMenuInfo) {

        super.onCreateContextMenu(contMenu, v, contextMenuInfo);
        ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) contextMenuInfo;

        int type = ExpandableListView.getPackedPositionType(info.packedPosition);
        int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
        int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);

        // Show context menu for groups
        if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
            contMenu.setHeaderTitle("Budget");
            contMenu.add(R.string.context_editBudget);
            contMenu.add(R.string.context_delBudget);

            // Show context menu for children
        } else if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
            contMenu.setHeaderTitle("Child");
            contMenu.add(R.string.context_editChild);
            contMenu.add(R.string.context_delChild);
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        Integer tmpInt = item.getItemId();
        ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item
                .getMenuInfo();

        int type = ExpandableListView.getPackedPositionType(info.packedPosition);
        int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
        int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
        //TextView vItem = info.targetView.findViewById(R.id.context_editBudget);

        if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
            //Toast.makeText(this, "Click auf Group: " + Integer.toString(item.getGroupId()), Toast.LENGTH_SHORT).show();

            if (item.getTitle().toString().equals(getString(R.string.context_editBudget))){
                Toast.makeText(this, "Edit Budget clicked in Budget Context Menu", Toast.LENGTH_SHORT).show();
            }

            if (item.getTitle().toString().equals(getString(R.string.context_delBudget))){
                int size = allGroups.get(groupPosition).children.size();
                for (int i = 0; i<size; i++) {
                    budgetDAO.delAllBudgetsForCategory(allGroups.get(groupPosition).catId);
                }
                allGroups.remove(groupPosition);
                //expAdapter.notifyDataSetChanged();
                if (allGroups.size() == 0){
                    Intent intent = new Intent(BudgetListActivity.this, MainActivity.class);
                    startActivity(intent);
                }
            }
        }

        if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {

            if (item.getTitle().toString().equals(getString(R.string.context_editChild))){
                Toast.makeText(this, "Edit Child clicked in Child Context Menu", Toast.LENGTH_SHORT).show();
            }

            if (item.getTitle().toString().equals(getString(R.string.context_delChild))){
                //wb, 27Oct2018: Delete the selected child for a budget with given category
                budgetDAO.delBudgetChildForCategory(Integer.parseInt(allGroups.get(groupPosition).children.get(childPosition).get(1)));
                allGroups.get(groupPosition).children.remove(childPosition);

                //expAdapter.notifyDataSetChanged();

                //wb, 28Oct2018: If no more budget rows available delete the whole budget for category
                if (allGroups.get(groupPosition).children.size() == 0) {
                    allGroups.remove(groupPosition);
                    //expAdapter.notifyDataSetChanged();
                    //expAdapter.notifyDataSetChanged();
                    if (allGroups.size() ==0){
                        Intent intent = new Intent(BudgetListActivity.this, MainActivity.class);
                        startActivity(intent);
                    }

                }
                /*
                else {
                    //allGroups.get(groupPosition).sumExpenses = 0.0;
                    //allGroups.get(groupPosition) = expAdapter.getSum(groupPosition)
                    for (int i = 0; i < allBudgetsList.size(); i++) {
                        if (allBudgetsList.get(i).getCategoryId() == allGroups.get(groupPosition).catId) {
                            allGroups.get(groupPosition).sumExpenses =
                                    allGroups.get(groupPosition).sumExpenses + allBudgetsList.get(i).getExpenses();
                        }
                    }
                }*/
            }
        }
        expAdapter.notifyDataSetChanged();
        //return super.onContextItemSelected(item);
        return true;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Budget budget = (Budget)adapter.getItem(position);
        editEntry(budget, position);
    }

    private void editEntry(Budget budget, int position) {
        Intent intent = new Intent(this, EditBudgetActivity.class);
        intent.putExtra("position", position);
        startActivityForResult(intent, REQUEST_CODE_EDIT);
    }
}

如您所见,我使用上下文菜单来编辑和删除组和/或子级。某些功能尚未完全实现。请了解,我将首先关注正确的ExpandableView填充的主要问题。

此外,其他事情-例如删除孩子后对费用的汇总进行不正确的更新-并不是很重要,将在以后进行。

这是组对象的类:

package com.wbapps.WBEasyBudgetManagement;

import java.util.ArrayList;
import java.util.List;

public class Group {
    public long budgetId;
    public long catId;

    public String category;
    public final List<List<String>> children = new ArrayList<List<String>>();
    public final List<Long> BudIds = new ArrayList<Long>();

    public double sumExpenses;

    public Group(String pcategory) {
        category = pcategory;
    }

}

这是ExpandableListAdapter的来源:

包com.wbapps.WBEasyBudgetManagement;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckedTextView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Currency;
import java.util.Locale;

public class ExpandableListAdapter extends BaseExpandableListAdapter{
    Context context;
    Locale locale;
    Currency curr;
    //array list to take the data for the list from the activity
    private final ArrayList<Group> allGroups;
    public LayoutInflater inflater;
    public AppCompatActivity activity;
    public int times = 0;

    //Constructor for ExpandableListAdapter
    //public ExpandableListAdapter(AppCompatActivity act, SparseArray<Group> groups) {
    public ExpandableListAdapter(AppCompatActivity act, ArrayList<Group> allGroups) {
        this.activity = act;
        this.allGroups = allGroups;
        inflater = act.getLayoutInflater();
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        times = times + 1;
        Log.d("Info getGroupView","In getGroupView " + Integer.toString(times) + " times");
        for (Locale wbLocale : Locale.getAvailableLocales()) {
            //Log.d("LOCALES", wbLocale.getLanguage() + "_" + wbLocale.getCountry() + " [" + wbLocale.getDisplayName() + "]");
            if (wbLocale.getCountry().equals("PH")) {
                curr = Currency.getInstance(wbLocale);
                curr.getSymbol(wbLocale);
                break;
            }
        }

        if (convertView == null || convertView.findViewById(R.id.tvCatGroup)==null){
            convertView = inflater.inflate(R.layout.list_row_group, null);
        }

        convertView = inflater.inflate(R.layout.list_row_group, null);
        String tmpCat = allGroups.get(groupPosition).category;
        Group tmpGroup = new Group(tmpCat);
        sortList();

        Group group = (Group) getGroup(groupPosition);
        //((CheckedTextView) convertView).setText(group.category + "\nTotal Expenses: " + group.sumExpenses + " " + curr.getSymbol());
        ((CheckedTextView) convertView).setText(group.category + "\nTotal Expenses: " + getSum(groupPosition) + " " + curr.getSymbol());
        ((CheckedTextView) convertView).setChecked(isExpanded);
        return convertView;
    }

    /* wb, 18Sep2017: sort the list_selectedShoppingItems list */
    public void sortList() {
        Collections.sort(allGroups, new Comparator<Group>() {
            @Override
            public int compare(Group content1, Group content2) {
                /* ignore case sensitivity */
                return content1.category.compareToIgnoreCase(content2.category);
            }
        });
    }

    @Override
    public View getChildView(int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent)
    {
        if(childPosition < getChildrenCount(groupPosition)-1) {
            //holds the detail string for one child
            final String children = (String) getChild(groupPosition, childPosition);
            if (convertView == null || convertView.findViewById(R.id.tvChildRow)==null)
                convertView = inflater.inflate(R.layout.list_row_details, null);

            convertView = inflater.inflate(R.layout.list_row_details, null);
            TextView txtChildRow = (TextView)convertView.findViewById(R.id.tvChildRow);
            txtChildRow.setText(children + " " + curr.getSymbol());
            convertView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(activity, children + " " + curr.getSymbol(),
                            Toast.LENGTH_SHORT).show();
                }
            });
        }

        //children is the last one
        if(childPosition == getChildrenCount(groupPosition)-1)
        {
            if (convertView == null || convertView.findViewById(R.id.tvSum)==null)
            convertView = inflater.inflate(R.layout.listview_footer,null);
            TextView txtFooter = (TextView)convertView.findViewById(R.id.tvSum);
            //txtFooter.setText("Total expenses: " + allGroups.get(groupPosition).sumExpenses + " " + curr.getSymbol() );
            txtFooter.setText("Total expenses: " + getSum(groupPosition) + " " + curr.getSymbol() );
            //Log.e(TAG, "getChildView - sumExpenses: "+txtFooter.getText().toString());
        }
        convertView.setLongClickable( true);
        return convertView;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {

        return allGroups.get(groupPosition).children.get(childPosition).get(0);
    }

    public Object getSum(int groupPosition) {
        return allGroups.get(groupPosition).sumExpenses;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return 0;
    }

    //Add 1 to childCount. The last row is used as footer to childView
    @Override
    public int getChildrenCount(int groupPosition) {
        return allGroups.get(groupPosition).children.size() +1;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return allGroups.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return allGroups.size();
    }

    @Override
    public void onGroupCollapsed(int groupPosition) {
        super.onGroupCollapsed(groupPosition);
    }

    @Override
    public void onGroupExpanded(int groupPosition) {
        super.onGroupExpanded(groupPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return 0;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }
}

一些说明可能会有所帮助: -在getChildrenCount中,我将大小增加了1,因为我使用了最后一个孩子作为页脚来显示费用汇总

    为了更好地理解,
  • 这里是列表“ allGroups”的图片 allGroups List

我希望我能为您提供所有必要的信息。请让我知道是否缺少某些物品。我会尽快添加。

希望有人在那里为我提供解决方案。 祝你今天愉快 安德烈亚斯(Andreas)

1 个答案:

答案 0 :(得分:0)

与此同时,我发现了这种行为的原因。适配器的源代码末尾有一个方法“ getGroupID”。此处的返回值设置为0,这引起了麻烦。必须将其设置为groupPosition,然后它才能工作!

@Override
public long getGroupId(int groupPosition) {
    /* wb, 10Nov2018: this statement was due to the error of deleting a last child of a group
    With "return 0" the children of the remaining group was shown twice !!!
    return 0;
    */
    return groupPosition;
}

这对所有也遇到此问题的人都是有帮助的。 玩得开心 安德烈亚斯(Andreas)