繁体   English   中英

我的RecyclerView过滤后不断重置

[英]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个潜在问题:

  1. 将filteredList传递给mListAdapter之后,必须调用adapter.notifyDataSetChanged notifyDataSetChanged来使列表视图无效。
  2. 此外,将过滤列表添加到适配器后,无需清除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) {

        }
    });

你犯了一个愚蠢的错误。 您还要清除并在实际列表中添加新值。 你不应该那样做。

  • 您只应解析在过滤器中获得的新列表[filterlist]
  • 并从afterTextChanged和加载项onTextChanged中删除以调用filter(s.toString())

例子:-

第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中的搜索,请参考以下链接:-

如何填充recyclerView

嗨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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM