我创建了RecyclerView,其中包含简单的单词列表(GroupVc对象的String名称)。由于列表可能很长,我想让它可以在工具栏中使用SearchView过滤。 我的应用程序的体系结构基于Android体系结构组件,其中所有GroupVc对象都存在于Room数据库中,并且通过ViewModel和Repository对象提供从UI对DataBase的访问。我在我的RecyclerView上提交了包含在LiveData中的所有GroupsVc的列表,以便更新它。 我的问题是我不知道如何使RecyclerView可过滤。我尝试在适配器中实现Filterable Interface:
public class GroupsVcAdapter extends
RecyclerView.Adapter<GroupsViewHolder> implements Filterable{
private LayoutInflater mInflater;
private List<GroupVc> mGroupsVc;
private List<GroupVc> filteredGroupsVc;
private OnItemClicked onClick;
public GroupsVcAdapter(Context context, OnItemClicked onClick) {
mInflater = LayoutInflater.from(context);
this.onClick = onClick;
}
public List<GroupVc> getmGroupsVc() {
return mGroupsVc;
}
@Override
public GroupsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.layout_list_of_groups, parent, false);
return new GroupsViewHolder(itemView, onClick);
}
@Override
public void onBindViewHolder(final GroupsViewHolder holder, int position) {
if (mGroupsVc != null) {
GroupVc current = mGroupsVc.get(position);
holder.getNameView().setText(current.getNameGroup());
} else {
holder.getNameView().setText(R.string.nogroups);
}
}
public void setGroupsVc(List<GroupVc> mGroupsVc) {
this.mGroupsVc = mGroupsVc;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
if (mGroupsVc != null)
return mGroupsVc.size();
else return 0;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mGroupsVc = (List<GroupVc>) results.values;
notifyDataSetChanged();
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
filteredGroupsVc = null;
if (constraint.length() == 0) {
filteredGroupsVc = mGroupsVc;
} else {
filteredGroupsVc = getFilteredResults(constraint.toString().toLowerCase());
}
FilterResults results = new FilterResults();
results.values = filteredGroupsVc;
return results;
}
};
}
protected List<GroupVc> getFilteredResults(String constraint) {
List<GroupVc> results = new ArrayList<>();
for (GroupVc item : mGroupsVc) {
if (item.getNameGroup().toLowerCase().contains(constraint)) {
results.add(item);
}
}
return results;
}
}
然后在活动I中写了一个方法:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_activity_words, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String text) {
return false;
}
@Override
public boolean onQueryTextChange(String text) {
adapter.getFilter().filter(text);
return true;
}
});
return true;
}
The result was that my RecyclerView got filtered correctly but it wasn't restored after I closed SearchView. The only way to do it is to reload activity. **So I'm interested in How can I restore RecyclerView's list and can I use for filtering any LiveData's capacities?** Below I post the complete code of Activity, ViewModel and Repository:
活动
public class GroupsActivity extends AppCompatActivity {
private static final String DELETE_DIALOG = "Delete dialog";
private static final String EDIT_DIALOG = "Edit dialog";
private RecyclerView mRecyclerView;
private GroupsVcAdapter adapter;
private GroupsViewModel mGroupsViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_groups);
//Creating of toolbar with title Groups
Toolbar myToolbar = findViewById(R.id.toolbar_groups);
setSupportActionBar(myToolbar);
//Enable Up Button
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
//RecyclerView containing the list of groups with sound icons
mRecyclerView = initRecyclerView();
//Using ViewModel to observe GroupVc data
mGroupsViewModel = ViewModelProviders.of(this).get(GroupsViewModel.class);
mGroupsViewModel.getAllGroups().observe(this, new Observer<List<GroupVc>>() {
@Override
public void onChanged(@Nullable List<GroupVc> groupVcs) {
adapter.setGroupsVc(groupVcs);
}
});
}
private RecyclerView initRecyclerView() {
RecyclerView recyclerView = findViewById(R.id.groups_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
OnItemClicked listener = (v, position) -> {
switch (v.getId()) {
case R.id.delete_group:
Log.i(DELETE_DIALOG, "Delete button");
break;
case R.id.edit_group:
Log.i(EDIT_DIALOG, "Edit button");
break;
case R.id.surface:
Log.i(SURFACE, "Surface button");
break;
}
};
adapter = new GroupsVcAdapter(this, listener);
recyclerView.setAdapter(adapter);
return recyclerView;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_activity_words, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String text) {
return false;
}
@Override
public boolean onQueryTextChange(String text) {
adapter.getFilter().filter(text);
return true;
}
});
return true;
}
}
视图模型
public class GroupsViewModel extends AndroidViewModel {
private LiveData<List<GroupVc>> mAllGroups;
private GroupRepository mRepository;
public GroupsViewModel(@NonNull Application application) {
super(application);
mRepository = new GroupRepository(application);
mAllGroups = mRepository.getAllGroupVc();
}
public LiveData<List<GroupVc>> getAllGroups() {
return mAllGroups;
}
}
存储库
public class GroupRepository {
private LiveData<List<GroupVc>> mAllGroups;
private GroupVcDao mGroupVcDao;
public GroupRepository(Application application) {
AppDatabase db = AppDatabase.getInstance(application);
mGroupVcDao = db.groupVcDao();
mAllGroups = mGroupVcDao.getAllGroupVc();
}
public LiveData<List<GroupVc>> getAllGroupVc() {
return mAllGroups;
}
}
答案 0 :(得分:0)
删除过滤器时数据未正确恢复的问题是,因为在发布过滤结果时会覆盖数据列表。
以下是解决方案:
public GroupsVcAdapter(Context context, OnItemClicked onClick) {
mInflater = LayoutInflater.from(context);
this.onClick = onClick;
// init the lists
mGroupsVc = new ArrayList<>();
filteredGroupsVc = new ArrayList<>();
}
public List<GroupVc> getFilteredGroupsVc() {
return filteredGroupsVc;
}
@Override
public int getItemCount() {
return filteredGroupsVc != null ? filteredGroupsVc.size() : 0;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredGroupsVc = (List<GroupVc>) results.values;
notifyDataSetChanged();
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
filteredGroupsVc.clear();
if (constraint.length() == 0) {
filteredGroupsVc.addAll(mGroupsVc);
else {
filteredGroupsVc = getFilteredResults(constraint.toString().toLowerCase());
}
FilterResults results = new FilterResults();
results.values = filteredGroupsVc;
results.count = filteredGroupsVc.size();
return results;
}
};
}
如果您为适配器设置了新的数据列表,则必须致电adapter.getFilter().filter(text);
或将最后一个过滤器字符串保存在适配器内,并在setGroupsVc()
内调用过滤器
注意:
如果您使用notifyDataSetChanged();
,则不会有任何动画。如果您想要动画,请使用其他通知方法。
希望这有帮助。
修改强>
同时更新onBindViewHolder()
以从过滤后的列表中获取数据。
@Override
public void onBindViewHolder(final GroupsViewHolder holder, int position) {
if (filteredGroupsVc != null) {
GroupVc current = filteredGroupsVc.get(position);
holder.getNameView().setText(current.getNameGroup());
} else {
holder.getNameView().setText(R.string.nogroups);
}
}
现在,您始终可以从筛选列表中获取数据。初始状态是您的列表为空。这就是你在RecyclerView
中看到的内容。如果您致电setGroupsVc()
,则为适配器设置新列表。请记住,您始终从筛选列表中获取数据。因此,您必须使用您设置为适配器的新列表(新数据)更新已过滤的列表(旧数据)。
您有两个选择:
setGroupsVc()
后,在外面拨打过滤器:像
...
setGroupsVc(yourNewList);
adapter.getFilter().filter(searchview.getQuery());
...
setGroupsVc()
:在适配器中添加新字段lastFilter
private String lastFilter = "";
在performFiltering()
内保存过滤字符串
lastFilter = contraint.toString();
至少在setGroupsVc()
public void setGroupsVc(List<GroupVc> mGroupsVc) {
this.mGroupsVc = mGroupsVc;
getFilter().filter(lastFilter);
// notifyDataSetChanged(); -> not necessary anymore because we already call this inside our filter
}