Search code examples
androidfirebaseandroid-recyclerviewgoogle-cloud-firestorefirebaseui

How to add search filter for RecyclerView while working with Firestore?


So, i'm trying to create app that shows list of writers(image,name,bio) and the thing is that I have problem implementing search functionality. The guide for working with RecyclerView I used is here.

Code: MainActivity

public class MainActivity extends AppCompatActivity {

private FirebaseFirestore db;
private FirestoreRecyclerAdapter adapter;
private LinearLayoutManager linearLayoutManager;//nodrosina kada veida recycle attelos
private List<Klasiki> list;

@BindView(R.id.imageRecycleView)
RecyclerView klasikiList;  //tas pats kas find by ID

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ButterKnife.bind(this);
    linearLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false);
    klasikiList.setLayoutManager(linearLayoutManager);
    db = FirebaseFirestore.getInstance();
    getList();


}

            //atgriez ierakstus no datubazes un nodrosina atteloshanu recycle view
private void getList(){
    Query query = db.collection("klasiki");
    FirestoreRecyclerOptions<Klasiki> response = new FirestoreRecyclerOptions.Builder<Klasiki>()
            .setQuery(query, Klasiki.class)
            .build();

    adapter = new FirestoreRecyclerAdapter<Klasiki, klasikiHolder>(response) {
        @Override
        protected void onBindViewHolder(final klasikiHolder holder, int position, final Klasiki model) {
            holder.name.setText(model.getName());
            holder.shortBio.setText(model.getShortBio());
            Glide.with(getApplicationContext()).load(model.getImage()).into(holder.image);


            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, BioActivity.class);

                            //Parnes mainigos uz bio activity
                    Bundle extras = new Bundle();
                    extras.putString("imageInfo", model.getImage());
                    extras.putString("nameInfo", model.getName());
                    extras.putString("bioInfo", model.getFullBio());
                    intent.putExtras(extras);
                    startActivity(intent);

                }
            });

        }

        @Override
        public klasikiHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.klasiki_layout, parent, false);
            return new klasikiHolder(view);
        }                       //nodrosina jauna ieraksta returnu

        @Override
        public void onError(FirebaseFirestoreException e) {
            Log.e("error", e.getMessage());
        }

    };

    adapter.notifyDataSetChanged();
    klasikiList.setAdapter(adapter);

}

        //izsauc mainigos
public class klasikiHolder extends RecyclerView.ViewHolder{
    @BindView(R.id.name)
    TextView name;
    @BindView(R.id.klasikiImage)
    ImageView image;
    @BindView(R.id.shortBio)
    TextView shortBio;


    public klasikiHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);

    }
}

@Override
protected void onStart() {
    super.onStart();
    adapter.startListening();

}

@Override
protected void onStop() {
    super.onStop();
    adapter.stopListening();
}

Constructor

public class Klasiki {
private String Name;
private String Image;
private String shortBio;
private String fullBio;

public Klasiki(){}

public Klasiki(String name, String image, String shortBio, String fullBio) {
    Name = name;
    Image = image;
    this.shortBio = shortBio;
    this.fullBio = fullBio;
}

public String getName() {
    return Name;
}

public void setName(String name) {
    Name = name;
}

public String getImage() {
    return Image;
}

public void setImage(String image) {
    Image = image;
}

public String getShortBio() {
    return shortBio;
}

public void setShortBio(String shortBio) {
    this.shortBio = shortBio;
}

public String getFullBio() {
    return fullBio;
}

public void setFullBio(String fullBio) {
    this.fullBio = fullBio;
}

}

I think I have to use other RecyclerViewthan FirestoreRecyclerOptions but i'm not sure, really new to android programming. :)

UPDATE: So I made something like this:

    @Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.search_menu, menu);
    // Retrieve the SearchView and plug it into SearchManager
    final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
    SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String text) {
            querySearch = db.collection("klasiki").whereEqualTo("name", text);
            if (!text.trim().isEmpty()){
                getList(querySearch);
                adapter.startListening();
            }
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if (newText.trim().isEmpty()){
                getList(queryFinal);
                adapter.startListening();
            }
            return false;
        }
    });

    return true;
}

Probably not the best solution, but now I have different problem.. Is there a way to make sub string searches for Firestore? Like db.collection("klasiki").whereEqualTo("name", Ja); And it shows names where it starts with Ja.


Solution

  • In order to search for a writter you need to create a Query.

    FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
    Query nameOfTheWritterQuery = rootRef.collection("writters")
        .whereEqualTo("writterName", "Eidemanis Roberts");
    

    Seeing your Klasiki class, I need to tell you that you do not respect Java Naming Conventions rules for all your fields and you can have problems while deserializing. Your model class should look like this:

    public class Klasiki {
        private String name, image, shortBio, fullBio;
    
        public Klasiki( ){}
    
        public Klasiki(String name, String image, String shortBio, String fullBio) {
            this.name = name;
            this.image = image;
            this.shortBio = shortBio;
            this.fullBio = fullBio;
        }
    
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
    
        public String getImage() {return image;}
        public void setImage(String image) {this.image = image;}
    
        public String getShortBio() {return shortBio;}
        public void setShortBio(String shortBio) {this.shortBio = shortBio;}
    
        public String getFullBio() {return fullBio;}
        public void setFullBio(String fullBio) {this.fullBio = fullBio;}
    }
    

    Please see the fields now. All start will small letter.