[英]Getting wrong position after Recyclerview filtering using SearchView
[英]My RecyclerView keeps getting reset after filtering
我有一個可正常使用的RecyclerView,我需要實現一個搜索欄。 我設法用EditText和TextWatcher創建了一個搜索欄,但是存在以下問題:
通常,我的列表根據當前項目的位置傳遞數據,並且當我過濾列表時,位置當然會被弄亂。
我遵循了一些指南,發現了解決方法:
private void filter(String text){
ArrayList<Item> filteredList = new ArrayList<>();
for (Item item : mList ) {
if(item.getName().toLowerCase().contains(text.toLowerCase())) {
filteredList.add(item);
}
}
mListAdapter.filterList(filteredList);
//when the app is done filtering, it clears the existing ArrayList and it adds just the filtered Items
mList.clear();
mList.addAll(filteredList);
}
這種方法的問題是,當發生mList.clear()時,我會丟失所有數據,僅保留過濾后的數據。 然后,當我從搜索欄中刪除文本時,我所擁有的只是一個空的RecyclerView。
我曾想過在EditText為null時嘗試將列表重置為原始狀態,但是我不知道該怎么做,而且也不理想。
誰能想到解決此問題的方法? 我真的很絕望:D
我的RecyclerView類:
public class ListFragment extends Fragment {
static final String EXTRA_NAME = "monumentname";
static final String EXTRA_NUMBER = "monumentnumber";
static final String EXTRA_REGION = "monumentregion";
static final String EXTRA_REGION2 = "monumentregion2";
static final String EXTRA_TOWN = "monumenttown";
static final String EXTRA_DESCRIPTION = "monumentdescription";
static final String EXTRA_WEB = "web";
private ListAdapter mListAdapter;
private ArrayList<Item> mList;
private RequestQueue mRequestQueue;
private Context mContext;
private InternetCheck internetCheck = new InternetCheck();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable final Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.fragment_list, container, false);
RecyclerView mRecyclerView = rootview.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
Button syncData = rootview.findViewById(R.id.sync_button);
final ProgressBar progressBar = rootview.findViewById(R.id.progressbar);
EditText editText = rootview.findViewById(R.id.edittext);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable s) {
filter(s.toString());
}
});
..........some other irrelevant stuff here
mListAdapter.setOnItemClickListener(new ListAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
Intent detailIntent = new Intent(getActivity(), SingleItem.class);
Item clickedItem = mList.get(position);
detailIntent.putExtra(EXTRA_NAME, clickedItem.getName());
detailIntent.putExtra(EXTRA_NUMBER, clickedItem.getNumber());
detailIntent.putExtra(EXTRA_REGION, clickedItem.getRegion());
detailIntent.putExtra(EXTRA_REGION2, clickedItem.getRegion2());
detailIntent.putExtra(EXTRA_TOWN, clickedItem.getTown());
detailIntent.putExtra(EXTRA_DESCRIPTION, clickedItem.getDescription());
detailIntent.putExtra(EXTRA_WEB, clickedItem.getWeb());
startActivity(detailIntent);
}
});
return rootview;
}
.......some onCreateView and stuff like that here
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
mListAdapter = new ListAdapter(mContext, mList);
mRequestQueue = Volley.newRequestQueue(mContext);
}
private void parseJSON() {
JsonObjectRequest request = new JsonObjectRequest("http://192.168.0.105/sestavsisvujsvetweb/api/seznammagnetek", null, new Response.Listener<JSONObject>() {
.....parsing my JSON here
mRequestQueue.add(request);
}
private CharSequence removeHtmlFrom(String html) {
return new HtmlCleaner().clean(html).getText();
}
@Override
public void onStop() {
super.onStop();
saveData();
}
private void saveData() {
SharedPreferences sharedPreferences = getContext().getSharedPreferences("shared preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
Gson gson = new Gson();
String json = gson.toJson(mList);
editor.putString("seznam magnetek", json);
editor.apply();
}
private void loadData() {
SharedPreferences sharedPreferences = getContext().getSharedPreferences("shared preferences", MODE_PRIVATE);
Gson gson = new Gson();
String json = sharedPreferences.getString("seznam magnetek", null);
Type type = new TypeToken<ArrayList<Item>>() {
}.getType();
mList = gson.fromJson(json, type);
if (mList == null || mList.isEmpty()) {
Toast.makeText(getContext(), "Seznam magnetek je prázdný. Aktualizujte prosím data z databáze.", Toast.LENGTH_SHORT).show();
mList = new ArrayList<>();
}
}
private void filter(String text) {
ArrayList<Item> filteredList = new ArrayList<>();
for (Item item : mList) {
if (item.getName().toLowerCase().contains(text.toLowerCase())) {
filteredList.add(item);
}
}
mListAdapter.filterList(filteredList);
mList.clear();
mList.addAll(filteredList);
}
}
您在這里有2個潛在問題:
adapter.notifyDataSetChanged
notifyDataSetChanged來使列表視圖無效。 mList
。 由於loadData
僅被調用一次,因此如果您第一次清除它,則列表中只剩下已過濾的項目。 即使刪除了過濾器字符串,該項目也不會添加回mList
。 請嘗試添加以下內容:
private void filter(String text){
ArrayList<Item> filteredList = new ArrayList<>();
for (Item item : mList ) {
if(item.getName().toLowerCase().contains(text.toLowerCase())) {
filteredList.add(item);
}
}
mListAdapter.filterList(filteredList);
mListAdapter.notifyDataSetChanged();
}
在您的RecyclerView Adapter類中,添加一個ValueFilter
和一個保存先前數據的ValueFilter
。
private ValueFilter valueFilter;
private ArrayList<Item> mListFull; // this arraylist contains previous data.
private ArrayList<Item> mList;
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
ValueFilter將顯示cannot resolve symbol 'ValueFilter'
,因此創建一個名為ValueFilter的類。
創建類ValueFilter
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String str = constraint.toString().toUpperCase();
Log.e("constraint", str);
FilterResults results = new FilterResults();
if (constraint.length() > 0) {
ArrayList<Item> filterList = new ArrayList<>();
for (int i = 0; i < mListFull.size(); i++) {
if ((mListFull.get(i).getName().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
Item item = mListFull.get(i);
filterList.add(item);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mListFull.size();
results.values = mListFull;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mList = (ArrayList<Item>) results.values;
notifyDataSetChanged();
}
}
現在在您的EditText TextChangedListener onTextChanged中
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
youradapter.getFilter().filter(charSequence.toString()); //Add this (change youradapter with the name of your recyclerview adapter.)
}
@Override
public void afterTextChanged(Editable s) {
}
});
你犯了一個愚蠢的錯誤。 您還要清除並在實際列表中添加新值。 你不應該那樣做。
例子:-
第1步: 在課堂上更改通話過濾器
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
filter(s.toString());
}
@Override
public void afterTextChanged(Editable s) {
// filter(s.toString());
}
});
第2步: 刪除過濾功能中該行下方的內容。
mList.clear();
mList.addAll(filteredList);
步驟3: 在您的適配器類中:
public void filterlist(List<Item> name) {
this.Listname = name;
notifyDataSetChanged();
}
要全面了解Recycleview中的搜索,請參考以下鏈接:-
嗨Etoile,
我們的樣本問題:
假設我們有一個相框,我們要做的就是將其一部分擦除一段時間,然后再顯示整個相框。
可能的解決方案:
我們可以將整個Frame的實例保存在某個地方,假設A = Frame的實例,然后我們可以說B =A。因此,我們可以將B用作主框架,將A用作備用框架。 在我們通過擦除一段時間來修改B幀之后,可以很容易地返回到先前的狀態,方法是說我們不想再次修改,則讓B =A。因為我們的A仍然保持其狀態。
代碼示例實現 (盡管已修改)
private ArrayList<Item> mList; //Aka A from our solution above
private ArrayList<Item> filteredList = new ArrayList<>();// Aka B from our solution above
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mListAdapter = new ListAdapter(mContext, filteredList);
loadData();
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2{
filter(s.toString()); // I feel like it will be faster filtering from here
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
/* Here, we load the lists of items and notify our adapter of the changes, the last time in this function does the nofity */
private void loadData() {
SharedPreferences sharedPreferences = getContext().getSharedPreferences("shared preferences", MODE_PRIVATE);
Gson gson = new Gson();
String json = sharedPreferences.getString("seznam magnetek", null);
mList = gson.fromJson(json, new TypeToken<ArrayList<Item>>(){}.getType(););
if (mList == null || mList.isEmpty()) {
Toast.makeText(getContext(), "Seznam magnetek je prázdný. Aktualizujte prosím data z databáze.", Toast.LENGTH_SHORT).show();
mList = new ArrayList<>();
}
filteredList = mList;
mListAdapter.notifyDataSetChanged();
}
//So, if nothing is typed in the EditText, we simply want to reset back to the //previous state else do as appropriate i.e modify filteredList and notify adapter
private void filter(String text){
if(text.isEmpty()){
filteredList = mList;
mListAdapter.notifyDataSetChanged();
}else{
filteredList.clear();
for (Item item : mList ) {
if(item.getName().toLowerCase().startsWith(text.toLowerCase())) {
filteredList.add(item); //Aka B from our solution above
}
}
//we have cleared and modified filteredList, all we need to do if notify adapter.
mListAdapter.notifyDataSetChanged();
}
}
請提交錯誤(如有),我們可以進行更正。 快樂的編碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.