使用 SQLite 的搜索结果更新 RecyclerView
Posted
技术标签:
【中文标题】使用 SQLite 的搜索结果更新 RecyclerView【英文标题】:Update RecyclerView with search results from SQLite 【发布时间】:2020-08-18 06:25:35 【问题描述】:我在使用 SearchView 结果更新 RecyclerView 时遇到了问题。 进行实际搜索似乎工作正常,因为我已经在“performFiltering”中逐步完成了代码,并且“publishResults”具有正确的列表。但我似乎无法弄清楚如何更新 RecyclerView。我已经盯着这段代码 3 天了,这可能是一个我忽略的简单解决方案。
我的电影片段
public class MyMoviesFragment extends Fragment
private SearchView searchView = null;
private SearchView.OnQueryTextListener queryTextListener;
private static final boolean DEFAULT_SORT_ORDER_IS_ASC = false;
private static final int MY_MOVIES_LOADER_ID = 173201;
private ArrayList<Movie> _movies = new ArrayList();
private ArrayList<Movie> _moviesRaw = new ArrayList();
private Button _btnMoviesNotFound;
private DBHandler _repository;
private MyMoviesAdapter _myMoviesAdapter;
private ProgressBar _progressBar;
private RecyclerView _rvMovies;
private SharedPreferences _preferences;
private View _view;
public MyMoviesFragment()
// Required empty public constructor
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
// inflater.inflate(R.menu.main, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
if (searchItem != null)
searchView = (SearchView) searchItem.getActionView();
if (searchView != null)
searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
queryTextListener = new SearchView.OnQueryTextListener()
@Override
public boolean onQueryTextChange(String newText)
Log.i("onQueryTextChange", newText);
_myMoviesAdapter.getFilter().filter(newText);
return true;
@Override
public boolean onQueryTextSubmit(String query)
Log.i("onQueryTextSubmit", query);
return true;
;
searchView.setOnQueryTextListener(queryTextListener);
super.onCreateOptionsMenu(menu, inflater);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
// Inflate the layout for this fragment
this._view = inflater.inflate(R.layout.fragment_my_movies, container, DEFAULT_SORT_ORDER_IS_ASC);
getActivity().setTitle(R.string.movies_fragment_title);
this._repository = DBHandler.getInstance(getActivity());
this._progressBar = (ProgressBar) this._view.findViewById(R.id.progressBar2);
this._progressBar.setVisibility(View.VISIBLE);
this._rvMovies = (RecyclerView) this._view.findViewById(R.id.rvMovies);
this._rvMovies.setLayoutManager(new LinearLayoutManager(getActivity()));
this._myMoviesAdapter = new MyMoviesAdapter(this._movies, this);
this._rvMovies.setAdapter(this._myMoviesAdapter);
this._btnMoviesNotFound = (Button) this._view.findViewById(R.id.btnMoviesNotFound);
if (savedInstanceState == null)
loadMyMoviesList();
return this._view;
public void loadMyMoviesList()
getLoaderManager().initLoader(MY_MOVIES_LOADER_ID, null, new LoaderManager.LoaderCallbacks<ArrayList<Movie>>()
@NonNull
@Override
public Loader<ArrayList<Movie>> onCreateLoader(int id, Bundle args)
return new MyMoviesLoader(MyMoviesFragment.this.getContext());
public void onLoadFinished(Loader<ArrayList<Movie>> loader, ArrayList<Movie> movies)
if (movies != null)
MyMoviesFragment.this._movies.clear();
Iterator it = movies.iterator();
while (it.hasNext())
MyMoviesFragment.this._movies.add((Movie) it.next());
MyMoviesFragment.this._moviesRaw = new ArrayList(MyMoviesFragment.this._movies);
MyMoviesFragment.this._myMoviesAdapter.notifyDataSetChanged();
MyMoviesFragment.this.displayListState();
public void onLoaderReset(Loader<ArrayList<Movie>> loader)
).forceLoad();
public void displayListState()
this._progressBar.setVisibility(View.GONE);
if (this._movies.size() < 1)
this._rvMovies.setVisibility(View.GONE);
this._btnMoviesNotFound.setVisibility(View.VISIBLE);
return;
this._btnMoviesNotFound.setVisibility(View.GONE);
this._rvMovies.setVisibility(View.VISIBLE);
MyMoviesAdapter
public class MyMoviesAdapter extends RecyclerView.Adapter<MyMoviesAdapter.ViewHolder> implements Filterable
private Activity _activity;
private ArrayList<Movie> _movieListFull;
private ArrayList<Movie> _movieListFiltered;
private DBHandler _repository = DBHandler.getInstance(this._activity);
private Fragment _fragment;
public MyMoviesAdapter(ArrayList<Movie> movies, Fragment fragment)
this._activity = fragment.getActivity();
this._fragment = fragment;
this._movieListFull = movies;
protected class ViewHolder extends RecyclerView.ViewHolder
private CardView cardMovie;
private TextView lblMovieTitle;
public ViewHolder(View itemView)
super(itemView);
this.cardMovie = (CardView) itemView.findViewById(R.id.cardMovie);
this.lblMovieTitle = (TextView) itemView.findViewById(R.id.lblMovieTitle);
// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_movie, parent, false));
// Replace the contents of a view (invoked by the layout manager)
// Binds the data to the Views in each row
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position)
// Get the data model based on position
Movie movie = _movieListFull.get(position);
viewHolder.lblMovieTitle.setText(String.valueOf(movie.getTitle()));
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount()
return this._movieListFull.size();
@Override
public Filter getFilter()
return new Filter()
@Override
protected FilterResults performFiltering(CharSequence charSequence)
String charString = charSequence.toString();
if (charString.isEmpty())
_movieListFiltered = _movieListFull;
else
ArrayList<Movie> filteredList = new ArrayList<>();
for (Movie movie : _movieListFull)
if (movie.getTitle().toLowerCase().contains(charString))
filteredList.add(movie);
_movieListFiltered = filteredList;
FilterResults filterResults = new FilterResults();
filterResults.values = _movieListFiltered;
filterResults.count = _movieListFiltered.size();
return filterResults;
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults)
_movieListFiltered = (ArrayList<Movie>) filterResults.values;
notifyDataSetChanged();
;
【问题讨论】:
【参考方案1】:如果 _movieListFull 是完整数据集,则应使用 _movieListFiltered 进行显示。因此 getItemCount() 和 onBindViewHolder() 应该参考 _movieListFiltered。
尝试以下更改:
public MyMoviesAdapter(ArrayList<Movie> movies, Fragment fragment)
this._activity = fragment.getActivity();
this._fragment = fragment;
this._movieListFiltered = movies;
_movieListFull = new ArrayList<>();
_movieListFull.addAll(movies);
// Replace the contents of a view (invoked by the layout manager)
// Binds the data to the Views in each row
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position)
// Get the data model based on position
Movie movie = _movieListFiltered.get(position);
viewHolder.lblMovieTitle.setText(String.valueOf(movie.getTitle()));
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount()
return this._movieListFiltered.size();
@Override
protected FilterResults performFiltering(CharSequence charSequence)
String charString = charSequence.toString();
if (charString.isEmpty())
//_movieListFiltered = _movieListFull;
_movieListFiltered.addAll(_movieListFull);
else
ArrayList<Movie> filteredList = new ArrayList<>();
for (Movie movie : _movieListFull)
if (movie.getTitle().toLowerCase().contains(charString))
filteredList.add(movie);
_movieListFiltered = filteredList;
FilterResults filterResults = new FilterResults();
filterResults.values = _movieListFiltered;
filterResults.count = _movieListFiltered.size();
return filterResults;
希望有帮助!
【讨论】:
以上是关于使用 SQLite 的搜索结果更新 RecyclerView的主要内容,如果未能解决你的问题,请参考以下文章
Apollo GraphQL 突变结果不使用 PostgreSQL 更新,但适用于 SQLite