I add and remove values from adapter objects through adapter's add() and clear() and they are removing and adding elements to a list, which is not referenced from any place inside the adapter. I have orig list, which sits outside the adapter and has a reference from inside the adapter to the not changing outside reference and inside the adapter I only have reference to a new list, which I filled using the old original list with the same objects. How come that the new list affects the old list?
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;
}
}
Why does the original list get edited while I change only the filtered list?
EDIT:
ArrayAdapter<com.anysoftkeyboard.ui.settings.LanguageItem> adapter = new LanguageItemArrayAdapter(getContext(), simpleLanguageItems, simpleLanguageItems);
((LanguageItemArrayAdapter) adapter).fillData();;
(I know the fix, I don't understand the reason - fix is in code below if you're struggling the problem with Custom Adapter Filter like I did.)
This code passes the same instance of ArrayList
to the LanguageItemArrayAdapter
new LanguageItemArrayAdapter(getContext(), simpleLanguageItems, simpleLanguageItems)
To understand why add(…)
and clear()
in ArrayAdapter
also modifies the same object you need to look at their implementations from source .
public void clear() {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.clear();
} else {
mObjects.clear();
}
…
}
…
}
clear()
will modify mObjects
and mOriginalValues
(you will notice that other functions in ArrayAdapter
do the same). You will need to read the code inside ArrayFilter
to understand how they are modified.
private class ArrayFilter extends Filter {
/*
mObjects will contain only items fulfilling the filter conditions.
Original items are copied into mOriginalValues
*/
}
Looking at the constructor (and constructor chain) you will find that your class constructor has
super(context, 0, filteredList);
that will end up calling
private ArrayAdapter(@NonNull Context context,
@LayoutRes int resource,
@IdRes int textViewResourceId,
@NonNull List<T> objects,
boolean objsFromResources) {
…
mObjects = objects;
…
}
This allows ArrayAdapter
to modify your simpleLanguageItems
instance.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.