Почему исходные элементы массива также удаляются в ArrayAdapter? - PullRequest
0 голосов
/ 30 сентября 2019

Я добавляю и удаляю значения из объектов адаптера через add () и clear () адаптера, и они удаляют и добавляют элементы в список, на который нет ссылок из любого места внутри адаптера. У меня есть список orig, который находится вне адаптера и имеет ссылку изнутри адаптера на неизменную внешнюю ссылку, а внутри адаптера у меня есть только ссылка на список новый , который я заполнил, используя старый оригиналсписок с одинаковыми объектами. Почему новый список влияет на старый список?

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();;

(Я знаю исправление, я не понимаю причину - исправление приведено в приведенном ниже коде, если вы пытаетесь решить проблему с фильтром настраиваемого адаптера, как я.)

1 Ответ

1 голос
/ 01 октября 2019

Этот код передает тот же экземпляр ArrayList в LanguageItemArrayAdapter

new LanguageItemArrayAdapter(getContext(), simpleLanguageItems, simpleLanguageItems)

Чтобы понять, почему add(…) и clear() в ArrayAdapter также изменяют тот же объект, который вам нужно посмотретьпри их реализации из source .

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

clear() изменит mObjects и mOriginalValues (вы заметите, что другие функции в 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 экземпляр.

...