In my application, I have a real-time database in Firebase containing Title, Image, Description, Search(an extra field that is not displayed in the app but used contains the text of title with small case letters to make search case insensitive). Currently when I type query same to same either in small case or capital or with mixture of both it searches perfect, but when I type some word that is in between the query it doesn't work For example if the query is "This is long title" when I type "long" it shows nothing. I'm stuck help he solve this.
I have used firebase ui library:
implementation 'com.firebaseui:firebase-ui-database:4.2.0'
Realtime Database Screenshot:
Here is my activity code:
package com.blogspot.atifsoftwares.firebaseproject;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import java.io.ByteArrayOutputStream;
public class PostsListActivity extends AppCompatActivity {
LinearLayoutManager mLayoutManager; //for sorting
SharedPreferences mSharedPref; //for saving sort settings
RecyclerView mRecyclerView;
FirebaseDatabase mFirebaseDatabase;
DatabaseReference mRef;
FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter;
FirebaseRecyclerOptions<Model> options;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts_list);
//Actionbar
ActionBar actionBar = getSupportActionBar();
//set title
mSharedPref = getSharedPreferences("SortSettings", MODE_PRIVATE);
String mSorting = mSharedPref.getString("Sort", "newest"); //where if no settingsis selected newest will be default
if (mSorting.equals("newest")) {
mLayoutManager = new LinearLayoutManager(this);
//this will load the items from bottom means newest first
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
} else if (mSorting.equals("oldest")) {
mLayoutManager = new LinearLayoutManager(this);
//this will load the items from bottom means oldest first
mLayoutManager.setReverseLayout(false);
mLayoutManager.setStackFromEnd(false);
}
//RecyclerView
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
//send Query to FirebaseDatabase
mFirebaseDatabase = FirebaseDatabase.getInstance();
mRef = mFirebaseDatabase.getReference("Data");
showData();
}
//show data
private void showData(){
options = new FirebaseRecyclerOptions.Builder<Model>().setQuery(mRef, Model.class).build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Model model) {
holder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflating layout row.xml
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
//item click listener
viewHolder.setOnClickListener(new ViewHolder.ClickListener() {
@Override
public void onItemClick(View view, int position) {
//get data from firebase at the position clicked
String mTitle = getItem(position).getTitle();
String mDesc = getItem(position).getDescription();
String mImage = getItem(position).getImage();
//pass this data to new activity
Intent intent = new Intent(view.getContext(), PostDetailActivity.class);
intent.putExtra("title", mTitle); // put title
intent.putExtra("description", mDesc); //put description
intent.putExtra("image", mImage); //put image url
startActivity(intent); //start activity
}
@Override
public void onItemLongClick(View view, int position) {
//Todo implement you on long click functionality here
}
});
return viewHolder;
}
};
//set layout as LinearLayout
mRecyclerView.setLayoutManager(mLayoutManager);
firebaseRecyclerAdapter.startListening();
//set adapter to firebase recycler view
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
//search data
private void firebaseSearch(String searchText) {
//convert string entered in SearchView to lowercase
String query = searchText.toLowerCase();
Query firebaseSearchQuery = mRef.orderByChild("search").startAt(query).endAt(query + "\uf8ff");
options = new FirebaseRecyclerOptions.Builder<Model>().setQuery(firebaseSearchQuery, Model.class).build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Model model) {
holder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflating layout row.xml
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
//item click listener
viewHolder.setOnClickListener(new ViewHolder.ClickListener() {
@Override
public void onItemClick(View view, int position) {
//get data from firebase at the position clicked
String mTitle = getItem(position).getTitle();
String mDesc = getItem(position).getDescription();
String mImage = getItem(position).getImage();
//pass this data to new activity
Intent intent = new Intent(view.getContext(), PostDetailActivity.class);
intent.putExtra("title", mTitle); // put title
intent.putExtra("description", mDesc); //put description
intent.putExtra("image", mImage); //put image url
startActivity(intent); //start activity
}
@Override
public void onItemLongClick(View view, int position) {
//Todo implement you on long click functionality here
}
});
return viewHolder;
}
};
//set layout as LinearLayout
mRecyclerView.setLayoutManager(mLayoutManager);
firebaseRecyclerAdapter.startListening();
//set adapter to firebase recycler view
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
//load data into recycler view onStart
@Override
protected void onStart() {
super.onStart();
if (firebaseRecyclerAdapter !=null){
firebaseRecyclerAdapter.startListening();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//inflate the menu; this adds items to the action bar if it present
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
firebaseSearch(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
//Filter as you type
firebaseSearch(newText);
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//handle other action bar item clicks here
if (id == R.id.action_sort) {
//display alert dialog to choose sorting
showSortDialog();
return true;
}
if (id == R.id.action_add) {
//start Add Post Activity
startActivity(new Intent(PostsListActivity.this, AddPostActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
private void showSortDialog() {
//options to display in dialog
String[] sortOptions = {" Newest", " Oldest"};
//create alert dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Sort by") //set title
.setIcon(R.drawable.ic_action_sort) //set icon
.setItems(sortOptions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// The 'which' argument contains the index position of the selected item
// 0 means "Newest" and 1 means "oldest"
if (which == 0) {
//sort by newest
//Edit our shared preferences
SharedPreferences.Editor editor = mSharedPref.edit();
editor.putString("Sort", "newest"); //where 'Sort' is key & 'newest' is value
editor.apply(); // apply/save the value in our shared preferences
recreate(); //restart activity to take effect
} else if (which == 1) {
{
//sort by oldest
//Edit our shared preferences
SharedPreferences.Editor editor = mSharedPref.edit();
editor.putString("Sort", "oldest"); //where 'Sort' is key & 'oldest' is value
editor.apply(); // apply/save the value in our shared preferences
recreate(); //restart activity to take effect
}
}
}
});
builder.show();
}
}
To gain access to the Firebase database, your project must be connected to Firebase, which can be done in the following way: On your browser, search Firebase console, go to Add project -> Enter project name -> choose default account for Firebase -> Create project. Ensure you have enabled the Realtime database.
getKey() returns the key (last part of the path) of the location of the Snapshot. getReference() returns the Reference for the location that generated this Snapshot. getValue() returns the data contained in this Snapshot. hasChild() returns true if the specified child path has (non-null) data.
Cloud Firestore is Firebase's newest database for mobile app development. It builds on the successes of the Realtime Database with a new, more intuitive data model. Cloud Firestore also features richer, faster queries and scales further than the Realtime Database. Realtime Database is Firebase's original database.
The limitToFirst() method is used to set a maximum number of children to be synced for a given callback. If we set a limit of 100, we will initially only receive up to 100 child_added events. If we have fewer than 100 messages stored in our Database, a child_added event will fire for each message.
when I type some word that is in between the query it doesn't work
This is happening because Firebase does not support native indexing or search for text fields in database properties. Additionally, downloading an entire node to search for fields client-side isn't practical at all. To enable full text search of your Firebase realtime database data, I recommend you to use a third-party search service like Algolia or Elasticsearch.
This is an example on how it works with Cloud Firestore but in the same way you can use it with Firebase realtime database.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With