android - RecyclerView 不会在新搜索中自行清除
问题描述
我正在开发这个简单的 Github 用户搜索应用程序:
每次我进行新搜索时,都没有清除 recyclerview,而是将新的搜索结果简单地附加到末尾,这不是我想要的。我在进行新搜索之前明确清除了搜索适配器,但似乎不正确。
一些相关代码:
MainActivity.java
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
who = query;
currentPage = 1;
searchAdapter.clear();
searchAdapter.notifyDataSetChanged();
doSearchUser(query, currentPage);
//searchAdapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
return true;
}
SearchAdapter.java
package com.divbyzero.app.githubusersearch.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.divbyzero.app.githubusersearch.R;
import com.divbyzero.app.githubusersearch.model.User;
import java.util.ArrayList;
import java.util.List;
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.SearchViewHolder> implements Filterable {
private List<User> fullSearchResult;
private List<User> filteredSearchResult;
private List<User> theData;
private Context ctxt;
class SearchViewHolder extends RecyclerView.ViewHolder {
ImageView github_profile_pic;
TextView github_login;
public SearchViewHolder(View itemView) {
super(itemView);
github_profile_pic = itemView.findViewById(R.id.github_profile_pic);
github_login = itemView.findViewById(R.id.github_login);
}
}
public SearchAdapter(Context ctxt, List<User> list) {
this.ctxt = ctxt;
theData = list;
}
public void clear() {
int size = theData.size();
theData.clear();
notifyItemRangeRemoved(0, size);
}
@NonNull
@Override
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_item,
parent, false);
return new SearchViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
User user = theData.get(position);
Glide.with(ctxt)
.load(user.getAvatarUrl())
.override(200, 200)
.into(holder.github_profile_pic);
holder.github_login.setText(user.getLogin());
}
@Override
public int getItemCount() {
return theData.size();
}
@Override
public Filter getFilter() {
return searchFilter;
}
private Filter searchFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<User> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(fullSearchResult);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (User item : fullSearchResult) {
if (item.getLogin().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredSearchResult.clear();
filteredSearchResult.addAll((List) results.values);
notifyDataSetChanged();
}
};
public void updateData(List<User> newList){
this.theData.clear();
this.theData.addAll(newList);
}
}
完整代码: https ://github.com/anta40/GithubUserSearch
更新:
在加载更多数据时,我发现:无法在滚动回调中调用此方法。滚动回调可能会在您无法更改 RecyclerView 数据的度量和布局传递期间运行。任何可能改变 RecyclerView 结构或适配器内容的方法调用都应该推迟到下一帧
所以数据加载部分本身是不正确的。
如何解决这个问题?
解决方案
有几个提示:
首先,适配器每次都返回完整列表的大小,但它应该返回过滤列表的大小;并且您需要在theData
没有执行过滤时将过滤后的列表初始化为原始列表( )。
所以,改变这个:
@Override
public int getItemCount() {
return theData.size();
}
至:
@Override
public int getItemCount() {
return filteredSearchResult == null ? 0 : filteredSearchResult.size();
}
并在一开始就初始化filteredSearchResult
(在适配器构造函数中)
public SearchAdapter(Context ctxt, List<User> list) {
this.ctxt = ctxt;
theData = list;
filteredSearchResult = list; // <<<<<<<<< here is the change
}
其次,您从原始列表中onBindViewHolder()
获取user
(不是过滤列表,因此很可能从未过滤列表中返回错误数据);所以也将其更改为过滤列表。
所以替换theData
为filteredSearchResult
@Override
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
User user = filteredSearchResult.get(position); // <<<<<<<<< here is the change
...
}
每当您清除/设置原始列表时,更改过滤列表
public void clear() {
int size = theData.size();
theData.clear();
filteredSearchResult.clear(); // <<<<<<<<< here is the change
notifyItemRangeRemoved(0, size);
}
public void updateData(List<User> newList){
this.theData.clear();
this.theData.addAll(newList);
filteredSearchResult.addAll(newList); // <<<<<<<<< here is the change
}
推荐阅读
- spring - Spring MVC 5 Rest API 使用 JAXB 将 XML 转换为 Bean
- android - 如何清除 Api 29 及更低版本上的 Windownsets 类型标志
- reactjs - 组件是否有可能知道它在哪里“实现”与“渲染”
- c# - WhiteStack 组合框获取所选项目
- c# - 需要帮助通过事件的日期
- c - C int 指针分段错误几种情况,无法解释行为
- powershell - 如何获取已安装设备的驱动程序密钥?
- mysql-workbench - SHOW VARIABLES LIKE "secure_file_priv" 显示 null 但在 my.ini 中它是 "secure_file_priv="c:/wamp64/tmp" "
- javascript - 如何获取 react UI 服务器的 IP 地址?
- c++ - 练习面试问题 C++ 的类型错误(AlgoExpert)