您好,登錄后才能下訂單哦!
使用Adapter結合Filter做過濾的時候,在分別繼承ArrayAdapter和BaseAdapter時遇到“想修改數據而錯誤修改了引用”的經典問題。記錄遇到的詳細情況以免再犯。
繼承ArrayAdapter:
private class MyAdapter extends ArrayAdapter<String> { private Context mContext; private int mResource; private List<String> mData; private MyFilter mFilter; public MyAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<String> objects) { //這里會將object賦值給父類的mObjects成員變量,問題的所在 super(context, resource, objects); this.mContext = context; this.mResource = resource; this.mData = objects; } @Override public int getCount() { return mData.size(); } @Nullable @Override public String getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { View view; if (convertView == null) { view = LayoutInflater.from(mContext).inflate(mResource, parent, false); } else { view = convertView; } TextView text = (TextView) view.findViewById(android.R.id.text1); text.setText(mData.get(position)); return view; } @NonNull @Override public Filter getFilter() { if (mFilter == null) { mFilter = new MyFilter(); } return mFilter; } private class MyFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { String filterString = constraint.toString().toLowerCase(); FilterResults results = new FilterResults(); //為null,表示沒有賦值過,這里的邏輯是mOriginalValues保存原始數據,而mData保存過濾后的數據 if (mOriginalValues == null) { mOriginalValues = new ArrayList<>(mData); } if (TextUtils.isEmpty(filterString)) { results.values = mOriginalValues; results.count = mOriginalValues.size(); } else { List<String> values = new ArrayList<>(mOriginalValues); List<String> newValues = new ArrayList<>(); for (int i = 0; i < values.size(); i++) { String value = values.get(i); if (value.contains(filterString)) { newValues.add(value); } } results.values = newValues; results.count = newValues.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { //mData.clear(); //mData.addAll((List<String>)results.values); //noinspection unchecked mData = (List<String>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } }
繼承BaseAdapter:
private class NewAdapter extends BaseAdapter{ private Context mContext; private int mResource; private List<String> mList; private ArrayFilter mFilter; public NewAdapter(Context context, int resource, List<String> list) { this.mContext = context; this.mList = list; this.mResource = resource; } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view ; if (convertView == null){ view = LayoutInflater.from(mContext).inflate(mResource, null, false); }else{ view = convertView; } ((TextView)view).setText((String)getItem(position)); return view; } public ArrayFilter getFilter(){ if (mFilter == null){ mFilter = new ArrayFilter(); } return mFilter; } private class ArrayFilter extends Filter{ @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); String filterString = constraint.toString().toLowerCase(); if (mOriginalValues == null){ mOriginalValues = new ArrayList<>(mList); } if (TextUtils.isEmpty(filterString)){ results.values = new ArrayList<>(mOriginalValues); results.count = mOriginalValues.size(); }else{ List<String> values = new ArrayList<>(mOriginalValues); List<String> newValues = new ArrayList<>(); for (int i = 0; i < values.size(); i++) { String value = values.get(i).toLowerCase(); if (value.contains(filterString)){ newValues.add(value); } } results.values = newValues; results.count = newValues.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { //noinspection unchecked mList = (List<String>)results.values; if (results.count > 0){ notifyDataSetChanged(); }else{ notifyDataSetInvalidated(); } } } }
問題描述:
繼承BaseAdapter的時候必須重寫getItem、getCount、getItemId等幾個方法,而繼承ArrayAdapter的時候只必須有父類相應參數列表的構造方法。我一開始習慣使用BaseAdapter,后來發現直接繼承ArrayAdapter代碼更簡潔。然后在結合使用Filter的時候出現了問題。
問題:修改數據集合后notifyDataSetChanged沒有改變。
例如(參照示例片段):
1、重寫ArrayAdapter的時候必須實現父類的構造方法(問題所在)。
2、執行new MyAdapter(this,resourceId, datas);
3、那么datas會最終賦值給ArrayAdapter的mObjects成員變量
4、此時MyAdapter中的mData和mObjects指向同一塊數據
5、如果沒有重寫getCount,則getCount=mObjects.size();
6、如果重寫了getCount(如下),則getCount=mData.size();
7、在使用Filter之后,修改mData指向過濾后的數據,然而mObjects并沒有改變
8、可是這里決定ListView數據集的是mObjects引用,并沒有相應更新
解決方法:
1、修改數據引用變量mData的同時,修改mObjects。
2、只使用mData,不使用mObjects(倒不如直接繼承BaseAdapter邏輯更清晰)
2、直接修改指向的數據集。mData.clear();mData.addAll()。
示例代碼片段:
//重寫getCount、getItem等方法,使用mData引用 public int getCount() { return mData.size(); } public MyAdapter(@NonNull Context context, @LayoutResint resource, @NonNull List<String> objects) { //這個父類構造方法會將objects保存到mObjects,作為數據集的真正引用 super(context, resource, objects); this.mData = objects; } public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull List<T> objects) { mContext = context; mInflater = LayoutInflater.from(context); mResource = mDropDownResource = resource; mObjects = objects;//如果要修改數據引用,那么應該修改mObjects,而不是mData mFieldId = textViewResourceId; } //直接修改數據的方式而不是修改引用變量: @Override protected void publishResults(CharSequence constraint, FilterResults results) { //noinspection unchecked //mList = (List<String>) results.values; mData.clear(); mData.addAll((List<String>)results.values);//直接修改引用的數據,而非引用本身 if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } }
總結:
無搜索功能的ListView
1、繼承ArrayAdapter代碼更簡潔
具備搜索功能的ListView
1、繼承BaseAdapter
2、繼承ArrayAdapter并重寫getItem、getCount等方法使用本類的引用變量
3、繼承ArrayAdapter,不改引用變量,直接修改數據集
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。