Multiple Filters and Sorting with Firebase Database in Android Android by Rajesh Kumar Sahanee - March 16, 2020April 14, 20200 Post Views: 5,715 Hello Friends, we have already seen how to make multiple filters and sorting in android before but today we are going to see multiple filters and sorting with Firebase Database in Android. I am sharing this because one of our visitor asked for. Firebase currently offers two types of database solution Realtime Database and Cloud Firestore. We are going to use Cloud Firestore here instead of Realtime Database because it is newest database and faster than Realtime Database. We are going to use same logic and method to filter and sort the items as Cloud Firestore supports limited compound queries. And if you are new to firebase then you can also check Firebase Cloud Firestore Database Example in Android. So, here is the code build.gradle (Project Level) build.gradle // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.google.gms:google-services:4.3.3'//added // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } 1234567891011121314151617181920212223242526272829 // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.google.gms:google-services:4.3.3'//added // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }} allprojects { repositories { google() jcenter() }} task clean(type: Delete) { delete rootProject.buildDir} build.gradle (Module Level) build.gradle apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services'//added android { compileSdkVersion 28 defaultConfig { applicationId "com.zatackcoder.filtersortfirebasedatabaseexample" minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //to fix Cannot fit requested classes in a single dex file error multiDexEnabled true //added } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation 'com.google.firebase:firebase-auth:19.2.0' //added implementation 'com.google.firebase:firebase-firestore:21.4.1' //added implementation 'androidx.recyclerview:recyclerview:1.1.0' //added //Cannot fit requested classes in a single dex file implementation 'com.android.support:multidex:1.0.3' //added } 12345678910111213141516171819202122232425262728293031323334353637383940414243 apply plugin: 'com.android.application'apply plugin: 'com.google.gms.google-services'//added android { compileSdkVersion 28 defaultConfig { applicationId "com.zatackcoder.filtersortfirebasedatabaseexample" minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //to fix Cannot fit requested classes in a single dex file error multiDexEnabled true //added } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation 'com.google.firebase:firebase-auth:19.2.0' //added implementation 'com.google.firebase:firebase-firestore:21.4.1' //added implementation 'androidx.recyclerview:recyclerview:1.1.0' //added //Cannot fit requested classes in a single dex file implementation 'com.android.support:multidex:1.0.3' //added} MainActivity.java MainActivity.java Java package com.zatackcoder.filtersortfirebasedatabaseexample; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button addItemB = findViewById(R.id.addItemB); Button viewItemsB = findViewById(R.id.viewItemsB); addItemB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, AddItemActivity.class)); } }); viewItemsB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, ViewItemsActivity.class)); } }); } } 12345678910111213141516171819202122232425262728293031323334 package com.zatackcoder.filtersortfirebasedatabaseexample; import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button addItemB = findViewById(R.id.addItemB); Button viewItemsB = findViewById(R.id.viewItemsB); addItemB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, AddItemActivity.class)); } }); viewItemsB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, ViewItemsActivity.class)); } }); }} activity_main.xml activity_main.xml XHTML <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <Button android:id="@+id/addItemB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Item" /> <Button android:id="@+id/viewItemsB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View Items" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> 12345678910111213141516171819202122232425262728 <?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <Button android:id="@+id/addItemB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Item" /> <Button android:id="@+id/viewItemsB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View Items" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> Item.java Item.java Java package com.zatackcoder.filtersortfirebasedatabaseexample.classes; import java.util.Comparator; public class Item { private String name; private String color; private Integer size; private Double price; public static final Comparator<Item> nameComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return o1.getName().compareTo(o2.getName()); } }; public static final Comparator<Item> sizeComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return o1.getSize() - o2.getSize(); } }; public static final Comparator<Item> priceComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return (int) (o1.getPrice() - o2.getPrice()); } }; /** * required to deserialize from firebase database */ public Item() {} public Item(String name, String color, Integer size, Double price) { this.name = name; this.color = color; this.size = size; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public Integer getSize() { return size; } //customised setter to overcome deserialize object error //java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to int public void setSize(Object size) { try { this.size = Integer.parseInt(size.toString()); } catch (Exception e) { this.size = 0; } } public Double getPrice() { return price; } //customised setter to overcome deserialize object error //java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to double public void setPrice(Object price) { try { this.price = Double.parseDouble(price.toString()); } catch (Exception e) { this.price = 0.00; } } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 package com.zatackcoder.filtersortfirebasedatabaseexample.classes; import java.util.Comparator; public class Item { private String name; private String color; private Integer size; private Double price; public static final Comparator<Item> nameComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return o1.getName().compareTo(o2.getName()); } }; public static final Comparator<Item> sizeComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return o1.getSize() - o2.getSize(); } }; public static final Comparator<Item> priceComparator = new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { return (int) (o1.getPrice() - o2.getPrice()); } }; /** * required to deserialize from firebase database */ public Item() {} public Item(String name, String color, Integer size, Double price) { this.name = name; this.color = color; this.size = size; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public Integer getSize() { return size; } //customised setter to overcome deserialize object error //java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to int public void setSize(Object size) { try { this.size = Integer.parseInt(size.toString()); } catch (Exception e) { this.size = 0; } } public Double getPrice() { return price; } //customised setter to overcome deserialize object error //java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to double public void setPrice(Object price) { try { this.price = Double.parseDouble(price.toString()); } catch (Exception e) { this.price = 0.00; } }} AddItemActivity.java AddItemActivity.java Java package com.zatackcoder.filtersortfirebasedatabaseexample; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.firestore.DocumentReference; import com.google.firebase.firestore.FirebaseFirestore; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; public class AddItemActivity extends AppCompatActivity { private FirebaseFirestore db; private EditText nameET; private EditText colorET; private EditText sizeET; private EditText priceET; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_item); // Access a Cloud Firestore instance from your Activity db = FirebaseFirestore.getInstance(); initControls(); } private void initControls() { nameET = findViewById(R.id.nameET); colorET = findViewById(R.id.colorET); sizeET = findViewById(R.id.sizeET); priceET = findViewById(R.id.priceET); Button saveB = findViewById(R.id.saveB); saveB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Add a new document with a generated ID db.collection("items") .add(new Item(nameET.getText().toString(), colorET.getText().toString(), Integer.parseInt(sizeET.getText().toString()), Double.parseDouble(priceET.getText().toString()))) .addOnSuccessListener(new OnSuccessListener<DocumentReference>() { @Override public void onSuccess(DocumentReference documentReference) { nameET.setText(""); colorET.setText(""); sizeET.setText(""); priceET.setText(""); Toast.makeText(getApplicationContext(), "Item Added with ID: " + documentReference.getId(), Toast.LENGTH_LONG).show(); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(getApplicationContext(), "Error Adding Item! - " + e, Toast.LENGTH_LONG).show(); } }); } }); } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 package com.zatackcoder.filtersortfirebasedatabaseexample; import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast; import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.tasks.OnFailureListener;import com.google.android.gms.tasks.OnSuccessListener;import com.google.firebase.firestore.DocumentReference;import com.google.firebase.firestore.FirebaseFirestore;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; public class AddItemActivity extends AppCompatActivity { private FirebaseFirestore db; private EditText nameET; private EditText colorET; private EditText sizeET; private EditText priceET; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_item); // Access a Cloud Firestore instance from your Activity db = FirebaseFirestore.getInstance(); initControls(); } private void initControls() { nameET = findViewById(R.id.nameET); colorET = findViewById(R.id.colorET); sizeET = findViewById(R.id.sizeET); priceET = findViewById(R.id.priceET); Button saveB = findViewById(R.id.saveB); saveB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Add a new document with a generated ID db.collection("items") .add(new Item(nameET.getText().toString(), colorET.getText().toString(), Integer.parseInt(sizeET.getText().toString()), Double.parseDouble(priceET.getText().toString()))) .addOnSuccessListener(new OnSuccessListener<DocumentReference>() { @Override public void onSuccess(DocumentReference documentReference) { nameET.setText(""); colorET.setText(""); sizeET.setText(""); priceET.setText(""); Toast.makeText(getApplicationContext(), "Item Added with ID: " + documentReference.getId(), Toast.LENGTH_LONG).show(); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(getApplicationContext(), "Error Adding Item! - " + e, Toast.LENGTH_LONG).show(); } }); } }); }} activity_add_item.xml activity_add_item.xml XHTML <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AddItemActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Item" android:textSize="18sp" android:textStyle="bold" /> <EditText android:id="@+id/nameET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:ems="10" android:hint="Name" /> <EditText android:id="@+id/colorET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Color" /> <EditText android:id="@+id/sizeET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Size" /> <EditText android:id="@+id/priceET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Price" /> <Button android:id="@+id/saveB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="Save" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 <?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AddItemActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Item" android:textSize="18sp" android:textStyle="bold" /> <EditText android:id="@+id/nameET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:ems="10" android:hint="Name" /> <EditText android:id="@+id/colorET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Color" /> <EditText android:id="@+id/sizeET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Size" /> <EditText android:id="@+id/priceET" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="Price" /> <Button android:id="@+id/saveB" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="Save" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> ItemAdapter.java ItemAdapter.java Java package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; import java.util.List; public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> { private final Context context; private final List<Item> items; public ItemAdapter(Context context, List<Item> items) { this.context = context; this.items = items; } @NonNull @Override public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false); return new ItemViewHolder(view); } @Override public void onBindViewHolder(@NonNull final ItemViewHolder itemViewHolder, final int position) { itemViewHolder.container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String message = "You clicked on " + items.get(position).getName() + " - color:" + items.get(position).getColor() + " | size:" + items.get(position).getSize() + " | price:" + items.get(position).getPrice(); Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } }); itemViewHolder.name.setText(items.get(position).getName()); itemViewHolder.color.setText("Color: " + items.get(position).getColor()); itemViewHolder.size.setText("Size: " + items.get(position).getSize()); itemViewHolder.price.setText("Price: " + items.get(position).getPrice()); } @Override public int getItemCount() { return items.size(); } public static class ItemViewHolder extends RecyclerView.ViewHolder { final View container; final TextView name; final TextView color; final TextView size; final TextView price; ItemViewHolder(View view) { super(view); container = view; name = view.findViewById(R.id.name); color = view.findViewById(R.id.color); size = view.findViewById(R.id.size); price = view.findViewById(R.id.price); } } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import android.widget.Toast; import androidx.annotation.NonNull;import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; import java.util.List; public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> { private final Context context; private final List<Item> items; public ItemAdapter(Context context, List<Item> items) { this.context = context; this.items = items; } @NonNull @Override public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false); return new ItemViewHolder(view); } @Override public void onBindViewHolder(@NonNull final ItemViewHolder itemViewHolder, final int position) { itemViewHolder.container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String message = "You clicked on " + items.get(position).getName() + " - color:" + items.get(position).getColor() + " | size:" + items.get(position).getSize() + " | price:" + items.get(position).getPrice(); Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } }); itemViewHolder.name.setText(items.get(position).getName()); itemViewHolder.color.setText("Color: " + items.get(position).getColor()); itemViewHolder.size.setText("Size: " + items.get(position).getSize()); itemViewHolder.price.setText("Price: " + items.get(position).getPrice()); } @Override public int getItemCount() { return items.size(); } public static class ItemViewHolder extends RecyclerView.ViewHolder { final View container; final TextView name; final TextView color; final TextView size; final TextView price; ItemViewHolder(View view) { super(view); container = view; name = view.findViewById(R.id.name); color = view.findViewById(R.id.color); size = view.findViewById(R.id.size); price = view.findViewById(R.id.price); } } } list_item.xml list_item.xml XHTML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:background="#ffffff" android:clickable="true" android:orientation="vertical" android:focusable="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Name" android:textFontWeight="bold" android:textSize="15dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/color" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Color: Red" android:textSize="12dp" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_margin="5dp" android:background="#ADABAB" /> <TextView android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Size: 10" android:textSize="12dp" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_margin="5dp" android:background="#ADABAB" /> <TextView android:id="@+id/price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Price: 100" android:textSize="12dp" /> </LinearLayout> </LinearLayout> </LinearLayout> 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:background="#ffffff" android:clickable="true" android:orientation="vertical" android:focusable="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Name" android:textFontWeight="bold" android:textSize="15dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/color" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Color: Red" android:textSize="12dp" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_margin="5dp" android:background="#ADABAB" /> <TextView android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Size: 10" android:textSize="12dp" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_margin="5dp" android:background="#ADABAB" /> <TextView android:id="@+id/price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Price: 100" android:textSize="12dp" /> </LinearLayout> </LinearLayout> </LinearLayout> ViewItemsActivity.java ViewItemsActivity.java Java package com.zatackcoder.filtersortfirebasedatabaseexample; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.firestore.FirebaseFirestore; import com.google.firebase.firestore.Query; import com.google.firebase.firestore.QuerySnapshot; import com.zatackcoder.filtersortfirebasedatabaseexample.adaptors.ItemAdapter; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ViewItemsActivity extends AppCompatActivity { private Query query; private List<Item> items = new ArrayList<>(); private RecyclerView mRecyclerView; private ItemAdapter mAdapter; private ProgressBar loadPB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_items); FirebaseFirestore db = FirebaseFirestore.getInstance(); query = db.collection("items"); initControls(); } private void initControls() { mRecyclerView = findViewById(R.id.recycler_view); mRecyclerView.setHasFixedSize(true); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); RadioButton rb = findViewById(R.id.sortByName); switch (Preferences.ORDER_BY) { case "name" : rb = findViewById(R.id.sortByName); break; case "size" : rb = findViewById(R.id.sortBySize); break; case "price" : rb = findViewById(R.id.sortByPrice); break; } rb.setChecked(true); loadPB = findViewById(R.id.loadPB); loadPB.setVisibility(View.VISIBLE); query.orderBy(Preferences.ORDER_BY).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { items = task.getResult().toObjects(Item.class); if(!Preferences.filters.isEmpty()) { ArrayList<Item> filteredItems = new ArrayList<>(); List<String> colors = Preferences.filters.get(Filter.INDEX_COLOR).getSelected(); List<String> sizes = Preferences.filters.get(Filter.INDEX_SIZE).getSelected(); List<String> prices = Preferences.filters.get(Filter.INDEX_PRICE).getSelected(); for (Item item : items) { boolean colorMatched = true; if (colors.size() > 0 && !colors.contains(item.getColor())) { colorMatched = false; } boolean sizeMatched = true; if (sizes.size() > 0 && !sizes.contains(item.getSize().toString())) { sizeMatched = false; } boolean priceMatched = true; if (prices.size() > 0 && !priceContains(prices, item.getPrice())) { priceMatched = false; } if (colorMatched && sizeMatched && priceMatched) { filteredItems.add(item); } } items = filteredItems; } mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); loadPB.setVisibility(View.GONE); } }); final LinearLayout sortContainerBackLL = findViewById(R.id.sortContainerBackLL); final LinearLayout sortContainerLL = findViewById(R.id.sortContainerLL); //sortContainerLL.setTranslationY(-sortContainerLL.getHeight()); sortContainerBackLL.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sortContainerLL.animate() .translationY(-sortContainerLL.getHeight()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { sortContainerLL.animate().setListener(null); sortContainerBackLL.setVisibility(View.GONE); } }); } }); Button sortB = findViewById(R.id.sortB); sortB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sortContainerBackLL.setVisibility(View.VISIBLE); sortContainerLL.animate().translationY(0); } }); Button filterB = findViewById(R.id.filterB); filterB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(ViewItemsActivity.this, FilterActivity.class)); } }); RadioGroup sortRG = findViewById(R.id.sortRG); sortRG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { Item[] itemsArr = new Item[items.size()]; itemsArr = items.toArray(itemsArr); switch (checkedId) { case R.id.sortByName: Arrays.sort(itemsArr, Item.nameComparator); Preferences.ORDER_BY = "name"; break; case R.id.sortBySize: Arrays.sort(itemsArr, Item.sizeComparator); Preferences.ORDER_BY = "size"; break; case R.id.sortByPrice: Arrays.sort(itemsArr, Item.priceComparator); Preferences.ORDER_BY = "price"; break; } items = Arrays.asList(itemsArr); mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); sortContainerLL.animate() .translationY(-sortContainerLL.getHeight()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { sortContainerLL.animate().setListener(null); sortContainerBackLL.setVisibility(View.GONE); } }); } }); } private boolean priceContains(List<String> prices, Double price) { boolean flag = false; for (String p : prices) { String[] tmpPrices = p.split("-"); if (price >= Double.parseDouble(tmpPrices[0]) && price <= Double.parseDouble(tmpPrices[1])) { flag = true; break; } } return flag; } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 package com.zatackcoder.filtersortfirebasedatabaseexample; import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.RadioButton;import android.widget.RadioGroup; import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView; import com.google.android.gms.tasks.OnCompleteListener;import com.google.android.gms.tasks.Task;import com.google.firebase.firestore.FirebaseFirestore;import com.google.firebase.firestore.Query;import com.google.firebase.firestore.QuerySnapshot;import com.zatackcoder.filtersortfirebasedatabaseexample.adaptors.ItemAdapter;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Item; import java.util.ArrayList;import java.util.Arrays;import java.util.List; public class ViewItemsActivity extends AppCompatActivity { private Query query; private List<Item> items = new ArrayList<>(); private RecyclerView mRecyclerView; private ItemAdapter mAdapter; private ProgressBar loadPB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_items); FirebaseFirestore db = FirebaseFirestore.getInstance(); query = db.collection("items"); initControls(); } private void initControls() { mRecyclerView = findViewById(R.id.recycler_view); mRecyclerView.setHasFixedSize(true); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); RadioButton rb = findViewById(R.id.sortByName); switch (Preferences.ORDER_BY) { case "name" : rb = findViewById(R.id.sortByName); break; case "size" : rb = findViewById(R.id.sortBySize); break; case "price" : rb = findViewById(R.id.sortByPrice); break; } rb.setChecked(true); loadPB = findViewById(R.id.loadPB); loadPB.setVisibility(View.VISIBLE); query.orderBy(Preferences.ORDER_BY).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { items = task.getResult().toObjects(Item.class); if(!Preferences.filters.isEmpty()) { ArrayList<Item> filteredItems = new ArrayList<>(); List<String> colors = Preferences.filters.get(Filter.INDEX_COLOR).getSelected(); List<String> sizes = Preferences.filters.get(Filter.INDEX_SIZE).getSelected(); List<String> prices = Preferences.filters.get(Filter.INDEX_PRICE).getSelected(); for (Item item : items) { boolean colorMatched = true; if (colors.size() > 0 && !colors.contains(item.getColor())) { colorMatched = false; } boolean sizeMatched = true; if (sizes.size() > 0 && !sizes.contains(item.getSize().toString())) { sizeMatched = false; } boolean priceMatched = true; if (prices.size() > 0 && !priceContains(prices, item.getPrice())) { priceMatched = false; } if (colorMatched && sizeMatched && priceMatched) { filteredItems.add(item); } } items = filteredItems; } mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); loadPB.setVisibility(View.GONE); } }); final LinearLayout sortContainerBackLL = findViewById(R.id.sortContainerBackLL); final LinearLayout sortContainerLL = findViewById(R.id.sortContainerLL); //sortContainerLL.setTranslationY(-sortContainerLL.getHeight()); sortContainerBackLL.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sortContainerLL.animate() .translationY(-sortContainerLL.getHeight()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { sortContainerLL.animate().setListener(null); sortContainerBackLL.setVisibility(View.GONE); } }); } }); Button sortB = findViewById(R.id.sortB); sortB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sortContainerBackLL.setVisibility(View.VISIBLE); sortContainerLL.animate().translationY(0); } }); Button filterB = findViewById(R.id.filterB); filterB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(ViewItemsActivity.this, FilterActivity.class)); } }); RadioGroup sortRG = findViewById(R.id.sortRG); sortRG.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { Item[] itemsArr = new Item[items.size()]; itemsArr = items.toArray(itemsArr); switch (checkedId) { case R.id.sortByName: Arrays.sort(itemsArr, Item.nameComparator); Preferences.ORDER_BY = "name"; break; case R.id.sortBySize: Arrays.sort(itemsArr, Item.sizeComparator); Preferences.ORDER_BY = "size"; break; case R.id.sortByPrice: Arrays.sort(itemsArr, Item.priceComparator); Preferences.ORDER_BY = "price"; break; } items = Arrays.asList(itemsArr); mAdapter = new ItemAdapter(getApplicationContext(), items); mRecyclerView.setAdapter(mAdapter); sortContainerLL.animate() .translationY(-sortContainerLL.getHeight()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { sortContainerLL.animate().setListener(null); sortContainerBackLL.setVisibility(View.GONE); } }); } }); } private boolean priceContains(List<String> prices, Double price) { boolean flag = false; for (String p : prices) { String[] tmpPrices = p.split("-"); if (price >= Double.parseDouble(tmpPrices[0]) && price <= Double.parseDouble(tmpPrices[1])) { flag = true; break; } } return flag; }} activity_view_items.xml activity_view_items.xml XHTML <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ViewItemsActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:orientation="horizontal"> <Button android:id="@+id/sortB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawableLeft="@drawable/ic_sort_black_24dp" android:text="Sort" /> <Button android:id="@+id/filterB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawableLeft="@drawable/ic_filter_list_black_24dp" android:text="Filter" /> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/sortContainerBackLL" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#C4000000" android:orientation="vertical" android:visibility="gone" tools:ignore="MissingConstraints" tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteY="0dp"> <LinearLayout android:id="@+id/sortContainerLL" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFFFF" android:orientation="vertical" tools:ignore="MissingConstraints" tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteY="0dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="SORT BY" android:textSize="15dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#929191" /> <RadioGroup android:id="@+id/sortRG" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp"> <RadioButton android:id="@+id/sortByName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Name" android:checked="true"/> <RadioButton android:id="@+id/sortBySize" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Size" /> <RadioButton android:id="@+id/sortByPrice" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Price" /> </RadioGroup> </LinearLayout> </LinearLayout> <ProgressBar android:id="@+id/loadPB" style="?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:progress="-1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 <?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ViewItemsActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:orientation="horizontal"> <Button android:id="@+id/sortB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawableLeft="@drawable/ic_sort_black_24dp" android:text="Sort" /> <Button android:id="@+id/filterB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawableLeft="@drawable/ic_filter_list_black_24dp" android:text="Filter" /> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/sortContainerBackLL" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#C4000000" android:orientation="vertical" android:visibility="gone" tools:ignore="MissingConstraints" tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteY="0dp"> <LinearLayout android:id="@+id/sortContainerLL" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFFFF" android:orientation="vertical" tools:ignore="MissingConstraints" tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteY="0dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="SORT BY" android:textSize="15dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#929191" /> <RadioGroup android:id="@+id/sortRG" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp"> <RadioButton android:id="@+id/sortByName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Name" android:checked="true"/> <RadioButton android:id="@+id/sortBySize" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Size" /> <RadioButton android:id="@+id/sortByPrice" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="rtl" android:text="Price" /> </RadioGroup> </LinearLayout> </LinearLayout> <ProgressBar android:id="@+id/loadPB" style="?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:progress="-1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> Filter.java Filter.java Java package com.zatackcoder.filtersortfirebasedatabaseexample.classes; import java.util.List; public class Filter { public static final Integer INDEX_COLOR = 0; public static final Integer INDEX_SIZE = 1; public static final Integer INDEX_PRICE = 2; private String name; private List<String> values; private List<String> selected; public Filter(String name, List<String> values, List<String> selected) { this.name = name; this.values = values; this.selected = selected; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getValues() { return values; } public void setValues(List<String> values) { this.values = values; } public List<String> getSelected() { return selected; } public void setSelected(List<String> selected) { this.selected = selected; } } 12345678910111213141516171819202122232425262728293031323334353637383940414243 package com.zatackcoder.filtersortfirebasedatabaseexample.classes; import java.util.List; public class Filter { public static final Integer INDEX_COLOR = 0; public static final Integer INDEX_SIZE = 1; public static final Integer INDEX_PRICE = 2; private String name; private List<String> values; private List<String> selected; public Filter(String name, List<String> values, List<String> selected) { this.name = name; this.values = values; this.selected = selected; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getValues() { return values; } public void setValues(List<String> values) { this.values = values; } public List<String> getSelected() { return selected; } public void setSelected(List<String> selected) { this.selected = selected; }} FilterActivity.java FilterActivity.java Java package com.zatackcoder.filtersortfirebasedatabaseexample; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.adaptors.FilterAdapter; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class FilterActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_filter); initControls(); } private void initControls() { RecyclerView filterRV = findViewById(R.id.filterRV); RecyclerView filterValuesRV = findViewById(R.id.filterValuesRV); filterRV.setLayoutManager(new LinearLayoutManager(this)); filterValuesRV.setLayoutManager(new LinearLayoutManager(this)); List<String> colors = Arrays.asList("Red", "Green", "Blue", "White", "Yellow"); if (!Preferences.filters.containsKey(Filter.INDEX_COLOR)) { Preferences.filters.put(Filter.INDEX_COLOR, new Filter("Color", colors, new ArrayList())); } List<String> sizes = Arrays.asList("10", "12", "14", "16", "18", "20", "30", "40"); if (!Preferences.filters.containsKey(Filter.INDEX_SIZE)) { Preferences.filters.put(Filter.INDEX_SIZE, new Filter("Size", sizes, new ArrayList())); } List<String> prices = Arrays.asList("0-100", "101-200", "201-300"); if (!Preferences.filters.containsKey(Filter.INDEX_PRICE)) { Preferences.filters.put(Filter.INDEX_PRICE, new Filter("Price", prices, new ArrayList())); } FilterAdapter filterAdapter = new FilterAdapter(Preferences.filters, filterValuesRV); filterRV.setAdapter(filterAdapter); Button clearB = findViewById(R.id.clearB); clearB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Preferences.filters.get(Filter.INDEX_COLOR).setSelected(new ArrayList()); Preferences.filters.get(Filter.INDEX_SIZE).setSelected(new ArrayList()); Preferences.filters.get(Filter.INDEX_PRICE).setSelected(new ArrayList()); startActivity(new Intent(FilterActivity.this, ViewItemsActivity.class)); finish(); } }); Button applyB = findViewById(R.id.applyB); applyB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(FilterActivity.this, ViewItemsActivity.class)); finish(); } }); } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 package com.zatackcoder.filtersortfirebasedatabaseexample; import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Button; import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.adaptors.FilterAdapter;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.ArrayList;import java.util.Arrays;import java.util.List; public class FilterActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_filter); initControls(); } private void initControls() { RecyclerView filterRV = findViewById(R.id.filterRV); RecyclerView filterValuesRV = findViewById(R.id.filterValuesRV); filterRV.setLayoutManager(new LinearLayoutManager(this)); filterValuesRV.setLayoutManager(new LinearLayoutManager(this)); List<String> colors = Arrays.asList("Red", "Green", "Blue", "White", "Yellow"); if (!Preferences.filters.containsKey(Filter.INDEX_COLOR)) { Preferences.filters.put(Filter.INDEX_COLOR, new Filter("Color", colors, new ArrayList())); } List<String> sizes = Arrays.asList("10", "12", "14", "16", "18", "20", "30", "40"); if (!Preferences.filters.containsKey(Filter.INDEX_SIZE)) { Preferences.filters.put(Filter.INDEX_SIZE, new Filter("Size", sizes, new ArrayList())); } List<String> prices = Arrays.asList("0-100", "101-200", "201-300"); if (!Preferences.filters.containsKey(Filter.INDEX_PRICE)) { Preferences.filters.put(Filter.INDEX_PRICE, new Filter("Price", prices, new ArrayList())); } FilterAdapter filterAdapter = new FilterAdapter(Preferences.filters, filterValuesRV); filterRV.setAdapter(filterAdapter); Button clearB = findViewById(R.id.clearB); clearB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Preferences.filters.get(Filter.INDEX_COLOR).setSelected(new ArrayList()); Preferences.filters.get(Filter.INDEX_SIZE).setSelected(new ArrayList()); Preferences.filters.get(Filter.INDEX_PRICE).setSelected(new ArrayList()); startActivity(new Intent(FilterActivity.this, ViewItemsActivity.class)); finish(); } }); Button applyB = findViewById(R.id.applyB); applyB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(FilterActivity.this, ViewItemsActivity.class)); finish(); } }); }} activity_filter.xml activity_filter.xml XHTML <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".FilterActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/filterRV" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="0" android:background="#F2F2F2" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/filterValuesRV" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:background="#ffffff" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:orientation="horizontal"> <Button android:id="@+id/clearB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Clear" /> <Button android:id="@+id/applyB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Apply" /> </LinearLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 <?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".FilterActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/filterRV" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="0" android:background="#F2F2F2" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/filterValuesRV" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:background="#ffffff" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:orientation="horizontal"> <Button android:id="@+id/clearB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Clear" /> <Button android:id="@+id/applyB" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Apply" /> </LinearLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> FilterAdapter.java FilterAdapter.java Java package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.HashMap; public class FilterAdapter extends RecyclerView.Adapter<FilterAdapter.MyViewHolder> { private final HashMap<Integer, Filter> filters; private final RecyclerView filterValuesRV; private int selectedPosition = 0; public FilterAdapter(HashMap<Integer, Filter> filters, RecyclerView filterValuesRV) { this.filters = filters; this.filterValuesRV = filterValuesRV; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.filter_item, viewGroup, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int position) { myViewHolder.container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { filterValuesRV.setAdapter(new FilterValuesAdapter(position)); selectedPosition = position; notifyDataSetChanged(); } }); filterValuesRV.setAdapter(new FilterValuesAdapter(selectedPosition)); myViewHolder.container.setBackgroundColor(selectedPosition == position ? Color.WHITE : Color.TRANSPARENT); myViewHolder.title.setText(filters.get(position).getName()); } @Override public int getItemCount() { return filters.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { final View container; final TextView title; MyViewHolder(View view) { super(view); container = view; title = view.findViewById(R.id.title); } } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.graphics.Color;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView; import androidx.annotation.NonNull;import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.HashMap; public class FilterAdapter extends RecyclerView.Adapter<FilterAdapter.MyViewHolder> { private final HashMap<Integer, Filter> filters; private final RecyclerView filterValuesRV; private int selectedPosition = 0; public FilterAdapter(HashMap<Integer, Filter> filters, RecyclerView filterValuesRV) { this.filters = filters; this.filterValuesRV = filterValuesRV; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.filter_item, viewGroup, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int position) { myViewHolder.container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { filterValuesRV.setAdapter(new FilterValuesAdapter(position)); selectedPosition = position; notifyDataSetChanged(); } }); filterValuesRV.setAdapter(new FilterValuesAdapter(selectedPosition)); myViewHolder.container.setBackgroundColor(selectedPosition == position ? Color.WHITE : Color.TRANSPARENT); myViewHolder.title.setText(filters.get(position).getName()); } @Override public int getItemCount() { return filters.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { final View container; final TextView title; MyViewHolder(View view) { super(view); container = view; title = view.findViewById(R.id.title); } } } filter_item.xml filter_item.xml XHTML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_marginRight="0dp" android:layout_marginBottom="5dp" android:background="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="Color" android:textFontWeight="bold" android:textSize="15dp" /> </LinearLayout> 1234567891011121314151617181920212223 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_marginRight="0dp" android:layout_marginBottom="5dp" android:background="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="Color" android:textFontWeight="bold" android:textSize="15dp" /> </LinearLayout> FilterValuesAdapter.java FilterValuesAdapter.java Java package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R; import com.zatackcoder.filtersortfirebasedatabaseexample.Preferences; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.List; public class FilterValuesAdapter extends RecyclerView.Adapter<FilterValuesAdapter.MyViewHolder> { private final Integer filterIndex; public FilterValuesAdapter(Integer filterIndex) { this.filterIndex = filterIndex; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.filter_value_item, viewGroup, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int position) { final Filter tmpFilter = Preferences.filters.get(filterIndex); myViewHolder.value.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<String> selected = tmpFilter.getSelected(); if(myViewHolder.value.isChecked()) { selected.add(tmpFilter.getValues().get(position)); tmpFilter.setSelected(selected); } else { selected.remove(tmpFilter.getValues().get(position)); tmpFilter.setSelected(selected); } Preferences.filters.put(filterIndex, tmpFilter); } }); myViewHolder.value.setText(tmpFilter.getValues().get(position)); if(tmpFilter.getSelected().contains(tmpFilter.getValues().get(position))) { myViewHolder.value.setChecked(true); } } @Override public int getItemCount() { return Preferences.filters.get(filterIndex).getValues().size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { final CheckBox value; MyViewHolder(View view) { super(view); value = view.findViewById(R.id.value); } } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 package com.zatackcoder.filtersortfirebasedatabaseexample.adaptors; import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.CheckBox; import androidx.annotation.NonNull;import androidx.recyclerview.widget.RecyclerView; import com.zatackcoder.filtersortfirebasedatabaseexample.R;import com.zatackcoder.filtersortfirebasedatabaseexample.Preferences;import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.List; public class FilterValuesAdapter extends RecyclerView.Adapter<FilterValuesAdapter.MyViewHolder> { private final Integer filterIndex; public FilterValuesAdapter(Integer filterIndex) { this.filterIndex = filterIndex; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.filter_value_item, viewGroup, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int position) { final Filter tmpFilter = Preferences.filters.get(filterIndex); myViewHolder.value.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<String> selected = tmpFilter.getSelected(); if(myViewHolder.value.isChecked()) { selected.add(tmpFilter.getValues().get(position)); tmpFilter.setSelected(selected); } else { selected.remove(tmpFilter.getValues().get(position)); tmpFilter.setSelected(selected); } Preferences.filters.put(filterIndex, tmpFilter); } }); myViewHolder.value.setText(tmpFilter.getValues().get(position)); if(tmpFilter.getSelected().contains(tmpFilter.getValues().get(position))) { myViewHolder.value.setChecked(true); } } @Override public int getItemCount() { return Preferences.filters.get(filterIndex).getValues().size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { final CheckBox value; MyViewHolder(View view) { super(view); value = view.findViewById(R.id.value); } } } filter_value_item.xml filter_value_item.xml XHTML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:clickable="true" android:orientation="vertical" android:focusable="true"> <CheckBox android:id="@+id/value" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Red" android:textFontWeight="bold" android:textSize="15dp" /> </LinearLayout> 123456789101112131415161718 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:clickable="true" android:orientation="vertical" android:focusable="true"> <CheckBox android:id="@+id/value" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Red" android:textFontWeight="bold" android:textSize="15dp" /> </LinearLayout> Preferences.java Preferences.java Java package com.zatackcoder.filtersortfirebasedatabaseexample; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.HashMap; public abstract class Preferences { public static final HashMap<Integer, Filter> filters = new HashMap<>(); public static String ORDER_BY = "name"; } 12345678910 package com.zatackcoder.filtersortfirebasedatabaseexample; import com.zatackcoder.filtersortfirebasedatabaseexample.classes.Filter; import java.util.HashMap; public abstract class Preferences { public static final HashMap<Integer, Filter> filters = new HashMap<>(); public static String ORDER_BY = "name";} Directory/Package Structure Video https://zatackcoder.com/wp-content/uploads/2020/03/FilterSortFirebaseDatabaseExample.mp4 AndroidStudio Project Download FilterSortFirebaseDatabaseExample AndroidStudio Project 1 file(s) 30.77 MB Download Thanks for Stoping by If you find this helpful then please do share