Android ExpandableListView填充了两次

时间:2014-12-16 00:02:53

标签: java android json expandablelistview

我正在使用可扩展列表视图分别在菜单中显示选项和子选项。进来的数据是正确的,但奇怪的是listview似乎为每个数据条目调用了两次getChild和getChildView,因此它被添加到视图两次。它迭代,然后似乎再次迭代。

示例:

类别:  -玩具  -电子产品  -汽车  -玩具  -电子产品  -Cars

预期: 分类:  -玩具  -电子产品  -Cars

我对Android和Java真的很陌生,所以我可能会犯一个菜鸟错误。我已经介入尝试找到一个重复数据的点,但我能找到的是getChild / getChildView被调用两次。

这是expandableListView适配器类:

    public class ExpandableListAdapter extends BaseExpandableListAdapter {
    private Context context;
    private ArrayList<String> filterHeaderList;
    // child data in format of header title, child title
    private HashMap<String, ArrayList<JSONObject>> filterOptionsMap;

    public ExpandableListAdapter(Context context, ArrayList<String> filterHeaders, HashMap<String, ArrayList<JSONObject>> filterChildListMap) {
        this.context = context;
        this.filterHeaderList = filterHeaders;
        this.filterOptionsMap = filterChildListMap;
    }

    @Override
    public String[] getChild(int groupPosition, int childPosititon) {
        JSONObject childObject = this.filterOptionsMap.get(this.filterHeaderList.get(groupPosition)).get(childPosititon);
        if (childObject != null) {
            Iterator<?> it = childObject.keys();
            String key = null;
            String value = null;
            if (it.hasNext()) {
                key = it.next().toString();
                try {
                    value = childObject.getString(key);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                String[] data = new String[2];
                data[0] = key;
                data[1] = value;
                return data;
            } else {
                return null;
            }
        }
        return null;
    }

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

    @Override
    public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        String childNum = null;
        String childText = null;
        final String[] childData = (String[]) getChild(groupPosition, childPosition);
        if (childData != null) {
            childNum = childData[0];
            childText = childData[1];
        }
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.ps_filter_sort_filter_expandable_child, null);
        }

        TextView tvChildTitle = (TextView) convertView.findViewById(R.id.ps_filter_sort_filter_expandable_child_title);

        tvChildTitle.setText(childText);
        tvChildTitle.setTag(R.id.ps_filter_sort_filter_expandable_child_title + groupPosition + childPosition, childNum);
        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return this.filterOptionsMap.get(this.filterHeaderList.get(groupPosition)).size();
    }

    @Override
    public String getGroup(int groupPosition) {
        return this.filterHeaderList.get(groupPosition);
    }

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

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        String headerTitle = (String) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.ps_filter_sort_filter_expandable_parent, null);
        }

        TextView tvGroupTitle = (TextView) convertView.findViewById(R.id.ps_filter_sort_filter_expandable_parent_title);
        tvGroupTitle.setTypeface(null, Typeface.BOLD);
        tvGroupTitle.setText(headerTitle);

        return convertView;
    }

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

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

然后我这样称呼它:

filterListAdapter = new ExpandableListAdapter(this.getActivity(), filterHeaderList, filterOptionsMap);
        // setting list adapter
        expListView.setAdapter(filterListAdapter);
        filterListAdapter.notifyDataSetChanged();

有理由以这种方式组织数据,我宁愿不介入。我能说的是HashMap“filterOptionsMap”是正确的,它没有重复或“filterHeaderList”

非常感谢任何帮助。我找不到有类似问题的人,而且我一直在敲打键盘。

谢谢。

P.S。 您还需要点击组标题两次以使其折叠,但一旦打开。我不知道它是否是相关的或预期的行为,但我希望只需轻轻一点即可将其打开或关闭。奖金积分也可以提供帮助。

这里要求的是一些与HashMap相关的附加代码:

private void prepareFilterListData(ArrayList<String> headerList, JSONObject[] categoryList, JSONObject[] sellerList, JSONObject[] typeList) {
    filterHeaderArrayList = headerList;
    filterOptionsMap = new HashMap<String, ArrayList<JSONObject>>();

    // Adding child data
    ArrayList<JSONObject> categories = new ArrayList<JSONObject>();
    if (categoryList != null && categoryList.length > 0) {
        for (JSONObject category : categoryList) {
            categories.add(category);
        }
    }

    ArrayList<JSONObject> sellers = new ArrayList<JSONObject>();
    if (sellerList != null && sellerList.length > 0) {
        for (JSONObject seller : sellerList) {
            sellers.add(seller);
        }
    }

    ArrayList<JSONObject> types = new ArrayList<JSONObject>();
    if (typeList != null && typeList.length > 0) {
        for (JSONObject type : typeList) {
            types.add(type);
        }
    }

    filterOptionsMap.put(filterHeaderArrayList.get(0), categories);
    filterOptionsMap.put(filterHeaderArrayList.get(1), sellers);
    filterOptionsMap.put(filterHeaderArrayList.get(2), types);
}


    filterHeaderList = Directory.getFilterOptions();
    filterCategoryList = Directory.getFilterCategories();
    filterSellerList = Directory.getFilterSellers();
    filterTypeList = Directory.getFilterTypes();

    // Forms data structures from given input
    if (filterHeaderList != null && filterCategoryList != null && filterSellerList != null && filterTypeList != null) {
        prepareFilterListData(filterHeaderList, filterCategoryList, filterSellerList, filterTypeList);


private JSONObject[] getFilterTypes(JSONObject productSearchSettings, String filterTypes) {
    JSONArray typesObj;
    JSONObject[] types;
    try {
        typesObj = productSearchSettings.optJSONArray(filterTypes);
        if (typesObj != null) {
            types = new JSONObject[typesObj.length()];
            for (int i = 0; i < typesObj.length(); i++) {
                String key = "type" + String.valueOf(i);
                String val = (String) typesObj.get(i).toString();
                types[i] = new JSONObject().put(key, val);
            }
            return types;
        } else {
            return null;
        }
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

private JSONObject[] getFilterSellers(JSONObject productSearchSettings, String filterSellers) {
    JSONObject sellersObj = null;
    JSONObject[] sellers;
    try {
        sellersObj = productSearchSettings.getJSONObject(filterSellers);
        if (sellersObj != null) {
            sellers = new JSONObject[sellersObj.length()];
            Iterator<?> it = sellersObj.keys();
            int i = 0;
            while (it.hasNext()) {
                String key = (String) String.valueOf(it.next().toString());
                String val = sellersObj.getString(key);
                sellers[i] = new JSONObject().put(key, val);
                i++;
            }
            return sellers;
        } else {
            return null;
        }
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

private JSONObject[] getFilterCategories(JSONObject productSearchSettings, String filterCategories) {
    JSONObject categoriesObj = null;
    JSONObject[] categories;
    try {
        categoriesObj = productSearchSettings.getJSONObject(filterCategories);
        if (categoriesObj != null) {
            categories = new JSONObject[categoriesObj.length()];
            Iterator<?> it = categoriesObj.keys();
            int i = 0;
            while (it.hasNext()) {
                String key = (String) String.valueOf(it.next().toString());
                String val = categoriesObj.getString(key);
                categories[i] = new JSONObject().put(key, val);
                i++;
            }
            return categories;
        } else {
            return null;
        }
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;

}

如前所述,但是进入适配器的hashmap是正确的。我通过调试验证了。

4 个答案:

答案 0 :(得分:7)

我终于找到了它。我非常感谢您的反馈和帮助。

在该组的点击事件中,我没有返回true表示已处理点击。我正在使用click事件来切换扩展。

我不知道为什么会造成重复,并且还需要两次点击才能关闭该群组,但切换该群组点击事件的回报会产生重大影响。

答案 1 :(得分:4)

我确信缺少"return true"可能是您系统中的原因,但由于它对我不起作用,我添加了答案,因为我找到了原因:

ExpandableListView doc:

  

注意:您不能使用值wrap_content   android:如果是XML的ExpandableListView的layout_height属性   父母的大小也没有严格规定(例如,如果   父是ScrollView你不能指定wrap_content,因为它   也可以是任何长度。但是,如果是,则可以使用wrap_content   ExpandableListView父级具有特定大小,例如100像素。

我的ExpandableListView实际上位于带有height="wrap_content"的LinearLayout中。将其设置为match_parent,瞧,问题解决了。

我不是100%肯定,但可能是因为未定义高度,因为重新调整了父级的大小,所以会调用两次getChildView。

它可能(我知道这是为了个人经验,在测试过程中改变几个参数通常不是一个好主意,因为它会导致对原因的误解),你还要在添加时将高度设置为match_parent return true并认为解决方案是后者。

如果您可以取消设置ExpandableListView容器的高度,或者将返回值设置为false并查看哪个是真正原因,那将对所有人有所帮助。如果两者都好,我们发现了2个原因。

答案 2 :(得分:0)

嗯......很抱歉,我仍然没有看到任何导致这种行为的事情。通常,这可能是由于在不知不觉中添加新内容造成的。通常是因为从适配器外部修改数据。

在您的情况下,适配器中的filterHeaderListDirectory.getFilterOptions()返回的列表是相同的列表。因此,如果您修改Directory.getFilterOptions()列表,那么您也会无意中修改适配器。当然,这种方法可能只是动态生成一个新列表,所以这可能不是你的担忧。

如果你是肯定的,filterHeaderList在getChildView和getGroupView调用期间是正确的,我不确定还有什么可能是错的。自定义组/子视图不会导致此问题。

我所能建议的是采取一些更积极的调试措施。基本上开始将Activity / Fragment剥离到裸骨。消除尽可能多的变量,以便您只是做最简单的情况......使用一些数据加载ExpandableListView和适配器。

您也可以尝试输入一些虚假数据。只需尝试一个带有一个组的子项目,看看它是否仍然会使所有内容加倍。

答案 3 :(得分:0)

这对我有用:在onGroupClick内部,删除对parent.expandGroup(groupPosition)的调用,并使其返回false;

expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            parent.expandGroup(groupPosition); // delete this
            Log.d(TAG, "onGroupClick: ");
            return false;
        }
    });