I have a fragment with RecyclerView and Room Database and I want to add a search view. I have successfully added the search icon and also added the code in the Fragment as well as Adapter. But the problem is that when I click on the Search icon, the screen is blank. Also, when I type anything it doesn't give me any result. If I close the Search View and click on back button, the RecyclerView in Fragment is no more visible. I have checked the solution online and it uses similar code. So, I can't understand what is the mistake in my code. can anyone help me please?
My Fragment Code '''
package com.nitin.roomrecyclerview;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuItemCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
public class FragmentStatus extends Fragment implements MyViewHolder.OnStatusListener, SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener {
private FragmentStatusViewModel mViewModel;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private MyAdapter mAdapter;
FloatingActionButton floatingActionButton;
Bundle bundletest;
Bundle bundletest1;
Status status;
private List<Status> statuses = new ArrayList<>();
public static FragmentStatus newInstance() {
return new FragmentStatus();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.main, menu);
MenuItem menuItem = menu.findItem(R.id.search);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(this);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
if (newText == null || newText.trim().isEmpty()) {
mAdapter.setfilter(statuses);
return false;
} else {
newText = newText.toLowerCase();
List<Status> newList = new ArrayList<>();
for (Status status : statuses) {
if (status.getTitle().toLowerCase().contains(newText)){
newList.add(status);
}
}
Toast.makeText(getActivity(), "newtext" + newText, Toast.LENGTH_SHORT).show();
mAdapter.setfilter(newList);
return true;
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.deleteallstatus:
FragmentStatusViewModel mViewModel = new ViewModelProvider(this).get(FragmentStatusViewModel.class);
mViewModel.deleteAllStatus();
Toast.makeText(getActivity(), "All Status Deleted", Toast.LENGTH_SHORT).show();
return true;
case R.id.action_settings:
Toast.makeText(getActivity(), "Setting Selected", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_status_fragment, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = (getActivity()).findViewById(R.id.statusRecyclerView);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
floatingActionButton = getActivity().findViewById(R.id.button_add_status);
floatingActionButton.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_fragmentStatus_to_updateFragment, null));
//status = new Status(title,description);
mAdapter = new MyAdapter(statuses, this);
recyclerView.setAdapter(mAdapter);
mViewModel = new ViewModelProvider(this).get(FragmentStatusViewModel.class);
mViewModel.getAllStatus().observe(getViewLifecycleOwner(), new Observer<List<Status>>() {
@Override
public void onChanged(List<Status> statuses) {
mAdapter.setStatuses(statuses);
}
});
if(getArguments() != null && getArguments().containsKey("ID") == true && bundletest != getArguments()){
int id = getArguments().getInt("ID", -1);
if(id == -1){
Toast.makeText(getActivity(), "Status can't be updated", Toast.LENGTH_LONG).show();
}
String title = getArguments().getString("title1");
String description = getArguments().getString("description1");
Status status = new Status(title,description);
mViewModel.update(status);
status.setId(id);
bundletest = getArguments();
Toast.makeText(getActivity(), "Status updated" + id, Toast.LENGTH_LONG).show();
}else if (getArguments() != null && !getArguments().containsKey("ID") && bundletest1 != getArguments()){
String title = getArguments().getString("title");
String description = getArguments().getString("description");
Status status = new Status(title,description);
mViewModel.insert(status);
bundletest1 = getArguments();
Toast.makeText(getActivity(), "Status saved", Toast.LENGTH_LONG).show();
}else {
Toast.makeText(getActivity(), "Statuses displayed!", Toast.LENGTH_SHORT).show();
}
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
mViewModel.delete(mAdapter.getStatusAt(viewHolder.getAdapterPosition()));
Toast.makeText(getActivity(), "Note Deleted", Toast.LENGTH_LONG).show();
}
}).attachToRecyclerView(recyclerView);
}
@Override
public void onStatusClick(Status status) {
Toast.makeText(getActivity(), "the id is " + status.getId(), Toast.LENGTH_SHORT).show();
Bundle bundle = new Bundle();
bundle.putInt("ID", status.getId());
bundle.putString("description", status.getDescription());
bundle.putString("title", status.getTitle());
Navigation.findNavController(getActivity().findViewById(R.id.recyclerLayout)).navigate(R.id.action_fragmentStatus_to_editStatusFragment, bundle);
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
mAdapter.setfilter(statuses);
return true;
}
}
'''
My Adapter Code
'''
package com.nitin.roomrecyclerview;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private List<Status> statuses = new ArrayList<>();
private MyViewHolder.OnStatusListener listener;
public MyAdapter(List<Status> statuses, MyViewHolder.OnStatusListener listener) {
this.statuses = statuses;
this.listener = listener;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.status_recyclerview, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view, listener, statuses);
return myViewHolder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Status status = statuses.get(position);
holder.title_template.setText(status.getTitle());
holder.description_template.setText(status.getDescription());
}
@Override
public int getItemCount() {
return statuses.size();
}
public void setStatuses(List<Status> statuses){
this.statuses = statuses;
notifyDataSetChanged();
}
public Status getStatusAt(int position){
return statuses.get(position);
}
public void setfilter(List<Status> newList){
statuses.clear();
statuses.addAll(newList);
notifyDataSetChanged();
}
}
'''
My ViewHolder Code
'''
package com.nitin.roomrecyclerview;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView title_template;
public TextView description_template;
private List<Status> statuses = new ArrayList<>();
OnStatusListener listener;
//Status status;
public MyViewHolder(@NonNull View itemView, OnStatusListener listener, List<Status> statuses) {
super(itemView);
this.title_template = itemView.findViewById(R.id.title_template);
this.description_template = itemView.findViewById(R.id.description_template);
this.listener = listener;
this.statuses = statuses;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
listener.onStatusClick(statuses.get(getAdapterPosition()));
}
interface OnStatusListener{
void onStatusClick(Status status);
}
}
'''
My Menu XML Code
'''
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
<item
android:id="@+id/deleteallstatus"
android:orderInCategory="100"
android:title="Delete all status"
app:showAsAction="never" />
<item
android:id="@+id/search"
android:orderInCategory="100"
android:icon="@drawable/ic_search"
app:showAsAction="ifRoom|collapseActionView"
android:title="Search"
app:actionViewClass="androidx.appcompat.widget.SearchView" />
</menu>
'''
As I am using LiveData...the code is as follows
I had to implement Filterable in Adapter...and then the codes as shown below.
In Fragment '''
package com.nitin.roomrecyclerview;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuItemCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
public class FragmentStatus extends Fragment implements MyViewHolder.OnStatusListener {
private FragmentStatusViewModel mViewModel;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private MyAdapter mAdapter;
FloatingActionButton floatingActionButton;
Bundle bundletest;
Bundle bundletest1;
private List<Status> statuses = new ArrayList<>();
public static FragmentStatus newInstance() {
return new FragmentStatus();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.main, menu);
MenuItem menuItem = menu.findItem(R.id.search);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
mAdapter.getFilter().filter(newText);
return true;
}
});
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.deleteallstatus:
FragmentStatusViewModel mViewModel = new ViewModelProvider(this).get(FragmentStatusViewModel.class);
mViewModel.deleteAllStatus();
Toast.makeText(getActivity(), "All Status Deleted", Toast.LENGTH_SHORT).show();
return true;
case R.id.action_settings:
Toast.makeText(getActivity(), "Setting Selected", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_status_fragment, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = (getActivity()).findViewById(R.id.statusRecyclerView);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
floatingActionButton = getActivity().findViewById(R.id.button_add_status);
floatingActionButton.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_fragmentStatus_to_updateFragment, null));
//status = new Status(title,description);
mAdapter = new MyAdapter(getActivity(), statuses, this);
recyclerView.setAdapter(mAdapter);
mViewModel = new ViewModelProvider(this).get(FragmentStatusViewModel.class);
mViewModel.getAllStatus().observe(getViewLifecycleOwner(), new Observer<List<Status>>() {
@Override
public void onChanged(List<Status> statuses) {
mAdapter.setStatuses(statuses);
}
});
if(getArguments() != null && getArguments().containsKey("ID") == true && bundletest != getArguments()){
int id = getArguments().getInt("ID", -1);
if(id == -1){
Toast.makeText(getActivity(), "Status can't be updated", Toast.LENGTH_LONG).show();
}
String title = getArguments().getString("title1");
String description = getArguments().getString("description1");
Status status = new Status(title,description);
mViewModel.update(status);
status.setId(id);
bundletest = getArguments();
Toast.makeText(getActivity(), "Status updated" + id, Toast.LENGTH_LONG).show();
}else if (getArguments() != null && !getArguments().containsKey("ID") && bundletest1 != getArguments()){
String title = getArguments().getString("title");
String description = getArguments().getString("description");
Status status = new Status(title,description);
mViewModel.insert(status);
bundletest1 = getArguments();
Toast.makeText(getActivity(), "Status saved", Toast.LENGTH_LONG).show();
}else {
Toast.makeText(getActivity(), "Statuses displayed!", Toast.LENGTH_SHORT).show();
}
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
mViewModel.delete(mAdapter.getStatusAt(viewHolder.getAdapterPosition()));
Toast.makeText(getActivity(), "Note Deleted", Toast.LENGTH_LONG).show();
}
}).attachToRecyclerView(recyclerView);
}
@Override
public void onStatusClick(Status status) {
Toast.makeText(getActivity(), "the id is " + status.getId(), Toast.LENGTH_SHORT).show();
Bundle bundle = new Bundle();
bundle.putInt("ID", status.getId());
bundle.putString("description", status.getDescription());
bundle.putString("title", status.getTitle());
Navigation.findNavController(getActivity().findViewById(R.id.recyclerLayout)).navigate(R.id.action_fragmentStatus_to_editStatusFragment, bundle);
}
}
'''
Adapter Code '''
package com.nitin.roomrecyclerview;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.RecyclerView;
import com.nitin.roomrecyclerview.ui.home.HomeFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> implements Filterable {
private static final String TAG = "TEST_1";
private List<Status> statuses;
private MyViewHolder.OnStatusListener listener;
ArrayList<Status> arrayList = new ArrayList<>();
Context context;
public MyAdapter(Context context, List<Status> statuses, MyViewHolder.OnStatusListener listener) {
this.statuses = statuses;
this.listener = listener;
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.status_recyclerview, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view, listener, statuses);
return myViewHolder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Status status = statuses.get(position);
holder.title_template.setText(status.getTitle());
holder.description_template.setText(status.getDescription());
}
@Override
public int getItemCount() {
return statuses.size();
}
public void setStatuses(List<Status> newstatuses) {
this.statuses = newstatuses;
arrayList.addAll(statuses);
notifyDataSetChanged();
}
public Status getStatusAt(int position) {
return statuses.get(position);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
constraint = constraint.toString().toLowerCase().trim();
statuses.clear();
if (constraint.length() == 0) {
statuses.addAll(arrayList);
} else {
for (Status item : arrayList) {
if (item.getTitle().toLowerCase(Locale.getDefault()).contains(constraint)
|| item.getDescription().toLowerCase(Locale.getDefault()).contains(constraint)) {
statuses.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = statuses;
results.count = statuses.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results.count == 0){
Toast.makeText(context, "No Results found", Toast.LENGTH_LONG).show();
notifyDataSetChanged();
}else {
notifyDataSetChanged();
}
}
};
}
}
'''