【问题标题】:Why the original array items are also get deleted in an ArrayAdapter?为什么原始数组项也会在 ArrayAdapter 中被删除?
【发布时间】:2019-09-30 14:26:22
【问题描述】:

我通过适配器的 add() 和 clear() 从适配器对象中添加和删除值,它们正在向列表中删除和添加元素,该列表未从适配器内部的任何位置引用。我有 orig 列表,它位于适配器外部,并且从适配器内部引用到不变的外部引用,而在适配器内部我只引用了一个 new 列表,我使用旧的具有相同对象的原始列表。为什么新列表会影响旧列表?

class LanguageItemArrayAdapter extends ArrayAdapter<com.anysoftkeyboard.ui.settings.LanguageItem>{
    private Context mContext;
    private final ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem> origList = new ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem>();
    private final ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem> filteredList = new ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem>();

    LanguageItemArrayAdapter(@NonNull Context context, @LayoutRes ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem> list, ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem> filteredList){
        super(context, 0, filteredList);
        mContext = context;
        origList.addAll(list); //THIS WORKS WELL. 
        //THIS BREAKS EVERYTHING -> 
        //origlist = list;
    }

    public void fillData(){
        filteredList.addAll(origList);
        notifyDataSetChanged();

    }

    @Override
    public View getView(int position,  View convertView, @NonNull ViewGroup parent) {
        View listItem = convertView;
        if (listItem == null)
            listItem = LayoutInflater.from(mContext).inflate(R.layout.languages_list_row, parent, false);
        com.anysoftkeyboard.ui.settings.LanguageItem currentItem = filteredList.get(position);

        TextView title = listItem.findViewById(R.id.title);
        title.setText(currentItem.getTitle());

        return listItem;
    }

    private Filter myFilter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults filterResults = new FilterResults();
            ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem> tempList=new ArrayList<com.anysoftkeyboard.ui.settings.LanguageItem>();
            //constraint is the result from text you want to filter against.
            //objects is your data set you will filter from
            if(constraint != null) {
                int length= origList.size();
                int i=0;
                while(i<length){
                    LanguageItem item= origList.get(i);
                    if(item.toString().toUpperCase().contains(constraint.toString().toUpperCase())) {
                        tempList.add(item);
                    }
                    i++;
                }
                //following two lines is very important
                //as publish result can only take FilterResults objects
                filterResults.values = tempList;
                filterResults.count = tempList.size();
            }

            return filterResults;
        }

        //HERE ARE THE AFFECTING METHODS:
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            filteredList.clear();

            clear(); //******THIS METHOD REMOVES THE VALUES from origList as well******
            filteredList.addAll((Collection<? extends LanguageItem>) results.values);
            notifyDataSetChanged();

            //*****THIS ADDS VALUES TO ORIG LIST AS WELL. WHY?*****
            for(LanguageItem item: filteredList)
                add(item); 

        }
    };

    @Override
    public Filter getFilter() {
        return myFilter;
    }
}

为什么我只更改过滤后的列表时会编辑原始列表?

编辑:

ArrayAdapter<com.anysoftkeyboard.ui.settings.LanguageItem> adapter = new LanguageItemArrayAdapter(getContext(), simpleLanguageItems, simpleLanguageItems);
    ((LanguageItemArrayAdapter) adapter).fillData();;

(我知道修复,但我不明白原因 - 如果您像我一样在自定义适配器过滤器上遇到问题,修复在下面的代码中。)

【问题讨论】:

  • 在构造函数中,我期望this.filteredList = filteredList; 或者更好地删除字段filteredList,因为它似乎是父类。代码似乎有点值得重新设计。
  • @Joop Eggen 如果你知道答案,请告诉我,如果需要我会重写编译并再次编辑。
  • 能否分享一下你如何构造参数listfilteredList的代码,以及你是如何调用LanguageItemArrayAdapter构造函数的代码?
  • @VitaliPom 对不起,对我来说太混乱了。我不一定比你“好”。
  • @Joop ♥ 很酷对不起。我有 2-3 个机器人会否决我在这里写的每一个问题,今天又发生了。我以为它又是其中之一。抱歉,是的,代码有点脏,需要清理。同时一般来说没关系,因为这个问题很有趣。我再次道歉,我发现好人很少。是的,当我在 repo 中修复时,我也会在这里修复。非常感谢!!!!

标签: java android android-arrayadapter deep-copy


【解决方案1】:

此代码将ArrayList 的相同实例传递给LanguageItemArrayAdapter

new LanguageItemArrayAdapter(getContext(), simpleLanguageItems, simpleLanguageItems)

要了解为什么ArrayAdapter 中的add(…)clear() 也会修改同一个对象,您需要从source 查看它们的实现。

public void clear() {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.clear();
        } else {
            mObjects.clear();
        }
        …
    }
    …
}

clear() 将修改mObjectsmOriginalValues(您会注意到ArrayAdapter 中的其他函数也是如此)。您需要阅读 ArrayFilter 中的代码以了解它们是如何被修改的。

private class ArrayFilter extends Filter {
  /* 
  mObjects will contain only items fulfilling the filter conditions. 
  Original items are copied into mOriginalValues 
  */
}

查看构造函数(和构造函数链)你会发现你的类构造函数有

super(context, 0, filteredList);

最终会调用

private ArrayAdapter(@NonNull Context context, 
        @LayoutRes int resource,
        @IdRes int textViewResourceId, 
        @NonNull List<T> objects, 
        boolean objsFromResources) {
    …
    mObjects = objects;
    …
}

这允许ArrayAdapter 修改您的simpleLanguageItems 实例。

【讨论】:

  • 你是我的英雄! ?
猜你喜欢
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 2017-11-13
  • 2021-03-11
  • 2016-06-24
  • 2015-06-06
相关资源
最近更新 更多