Я работаю над проектом, в котором пользователь должен иметь возможность искать книгу по названию книги или году в списке массивов.
Я использую RecyclerView и SearchView, и я инициализировал их во фрагменте.
Я использую SearchView, совместимый с androidx, для фильтрации списка книг.
Насколько мне известно, я реализовал правильную логику c, однако, вид поиска, похоже, не фильтруется. какие-либо предложения?
BookListFragment. java
public class BookListFragment extends Fragment implements SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener {
public interface OnListFragmentInteractionListener {
void onListFragmentRefreshRequested();
}
private static final String ON_REFRESH_NOTED = "ON_REFRESH_NOTED";
private OnListFragmentInteractionListener mListener;
private ArrayList<Book> mBooks =
new ArrayList<>();
private BookRecyclerViewAdapter mBookAdapter =
new BookRecyclerViewAdapter(mBooks);
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeToRefreshView;
protected BookViewModel bookViewModel;
public BookListFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_book_list,
container, false);
mRecyclerView = view.findViewById(R.id.list);
mSwipeToRefreshView = view.findViewById(R.id.swiperefresh);
setHasOptionsMenu(true);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set the Recycler View adapter
Context context = view.getContext();
mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
mRecyclerView.setAdapter(mBookAdapter);
setHasOptionsMenu(true);
// Setup the swipe to refresh view
mSwipeToRefreshView.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Log.i(ON_REFRESH_NOTED, "Refresh noted.");
updateBooks();
}
}
);
}
private void updateBooks() {
if (mListener != null)
mListener.onListFragmentRefreshRequested();
}
public void setBooks(List<Book> books) {
mBooks.clear();
mBookAdapter.notifyDataSetChanged();
for (Book book : books) {
if (!mBooks.contains(book)) {
mBooks.add(book);
mBookAdapter
.notifyItemInserted(mBooks.indexOf(book));
}
}
mSwipeToRefreshView.setRefreshing(false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Retrieve the Book View Model for the parent Activity.
bookViewModel = new ViewModelProvider(getActivity()).get(BookViewModel.class);
// Get the data from the View Model, and observe any changes.
bookViewModel.getBooks()
.observe(getViewLifecycleOwner(), new Observer<List<Book>>() {
@Override
public void onChanged(List<Book> books) {
// When the View Model changes, update the List.
if (books != null)
setBooks(books);
}
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mListener = (OnListFragmentInteractionListener) context;
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NotNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
MenuItem itemSwitch = menu.findItem(R.id.action_switch);
SwitchCompat switchCompat = (SwitchCompat) itemSwitch.getActionView();
switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Toast.makeText(getContext().getApplicationContext(), "Formatting in XML..", Toast.LENGTH_SHORT).show();
bookViewModel.loadBooksInXML();
} else {
Toast.makeText(getContext().getApplicationContext(), "Formatting in JSON..", Toast.LENGTH_SHORT).show();
}
}
});
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return false;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
mBookAdapter.getFilter().filter(newText);
return true;
}
BookRecyclerViewAdapter. java
public class BookRecyclerViewAdapter extends
RecyclerView.Adapter<BookRecyclerViewAdapter.ViewHolder> implements Filterable {
private List<Book> mBooks;
private List<Book> mBooksFull;
private static final SimpleDateFormat TIME_FORMAT =
new SimpleDateFormat("y", Locale.UK);
private static final NumberFormat PRICE_FORMAT =
new DecimalFormat("0.0");
public BookRecyclerViewAdapter(List<Book> books) {
mBooks = books;
mBooksFull = books;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ListItemBookBinding binding = ListItemBookBinding.inflate(
LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Book book = mBooks.get(position);
holder.binding.setBook(book);
holder.binding.executePendingBindings();
}
@Override
public int getItemCount() {
return mBooks.size();
}
@Override
public Filter getFilter() {
return filter;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final ListItemBookBinding binding;
public ViewHolder(ListItemBookBinding binding) {
super(binding.getRoot());
this.binding = binding;
binding.setTimeformat(TIME_FORMAT);
binding.setPriceformat(PRICE_FORMAT);
}
}
private Filter filter = new Filter() {
// Running on background thread automatically
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Book> filteredList = new ArrayList<>();
if (constraint != null && constraint.length() > 0) {
filteredList.addAll(mBooksFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Book item : mBooksFull) {
if (item.getTitle().toLowerCase().contains(filterPattern) ||
item.getYear().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
} else {
filteredList = mBooksFull;
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
// Runs on a UI thread.
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mBooks.clear();
mBooks.addAll((List) results.values);
notifyDataSetChanged(); // notifies the data with new filtered values
}
};
BookMainActivity. java
public class BookMainActivity extends AppCompatActivity
implements BookListFragment.OnListFragmentInteractionListener {
@Override
public void onListFragmentRefreshRequested() {
updateBooks();
}
private void updateBooks() {
bookViewModel.loadBooksInXML();
bookViewModel.loadBooksInJson();
}
private static final String TAG_LIST_FRAGMENT = "TAG_LIST_FRAGMENT";
BookListFragment mBookListFragment;
BookViewModel bookViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_main);
FragmentManager fm = getSupportFragmentManager();
// Android will automatically re-add any Fragments that
// have previously been added after a configuration change,
// so only add it if this isn't an automatic restart.
if (savedInstanceState == null) {
FragmentTransaction ft = fm.beginTransaction();
mBookListFragment = new BookListFragment();
ft.add(R.id.main_activity_frame,
mBookListFragment, TAG_LIST_FRAGMENT);
ft.commitNow();
} else {
mBookListFragment =
(BookListFragment) fm.findFragmentByTag(TAG_LIST_FRAGMENT);
}
// Retrieve the Book View Model for this activity.
bookViewModel = new ViewModelProvider(this).get(BookViewModel.class);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
}