Display Data from Firestore on a RecyclerView using Kotlin
You need to provide default values to your model fields. Firestore will assign that default value to the field in case that particular field is missing from the document snapshot.
data class Proyecto(
val alcances: String = "",
val alumnos: HashMap<String, Any> = hashMapOf(),
val areasConoc: String = "",
val asignaturas: String = "",
val cliente: String = "",
val colaboradores: String = "",
val compDes: String = "",
val compPrev: String = "",
val coordinador: String = "",
val departamentos: String = "",
val impacto: String = "",
val institucion: String = "",
val justificacion: String = "",
val limityrest: String = "",
val materiaEje: String = "",
val periodo: HashMap<String, Any> = hashMapOf(),
val plan: String = "",
val planteamiento: String = "",
val profeResp: String = "",
val tipoejec: String = "",
val tituloproyecto: String = ""
)
Also, it is recommended to use Kotlin's immutable Map
instead of Java's HashMap
.
How to display data from Firestore in a RecyclerView with Android?
Assuming you have a Firestore database structure that looks like this:
Firestore-root
|
--- products (collection)
|
--- documentIdOne (document)
| |
| --- productName: "Milk"
|
--- documentIdTwo (document)
| |
| --- productName: "Soy Milk"
|
--- documentIdThree (document)
|
--- productName: "Bacon"
A model class that looks also like this:
public class ProductModel {
private String productName;
public ProductModel() {}
public ProductModel(String productName) {this.productName = productName;}
public String getProductName() {return productName;}
}
And a .XML
file that contains a RecyclerView
which also looks like this:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycler_view"/>
To display all the product names, please follow the next steps.
First, you need to find the RecyclerView
in your activity and set the LinearLayoutManager
like this:
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Then you need to create the root reference of your Firestore database and a Query
object like this:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.collection("products")
.orderBy("productName", Query.Direction.ASCENDING);
Then you'll have to create a FirestoreRecyclerOptions
object like this:
FirestoreRecyclerOptions<ProductModel> options = new FirestoreRecyclerOptions.Builder<ProductModel>()
.setQuery(query, ProductModel.class)
.build();
In your activity class, create a holder
class that looks like this:
private class ProductViewHolder extends RecyclerView.ViewHolder {
private View view;
ProductViewHolder(View itemView) {
super(itemView);
view = itemView;
}
void setProductName(String productName) {
TextView textView = view.findViewById(R.id.text_view);
textView.setText(productName);
}
}
Then create an adapter
which is declared as global:
private FirestoreRecyclerAdapter<ProductModel, ProductViewHolder> adapter;
And instantiate it in your activity like this:
adapter = new FirestoreRecyclerAdapter<ProductModel, ProductViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull holder productViewHolder, int position, @NonNull ProductModel productModel) {
holder.setProductName(productModel.getProductName());
}
@NonNull
@Override
public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_product, parent, false);
return new ProductViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
In the end, don't forget to override the following two methods and start listening for changes:
@Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
@Override
protected void onStop() {
super.onStop();
if (adapter != null) {
adapter.stopListening();
}
}
The result is this:
Edit:
If you want to display a toast message when the user clicks on an item, please add the following lines of code inside the setProductName()
method from the ProductViewHolder
class:
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), productName, Toast.LENGTH_SHORT).show();
}
});
Data from Firestore is not displayed in RecyclerView
I have set my database rule to allow read, write: if true; but still didn't work.
If you set:
allow read, write: if true;
In your Security Rules, it means that you allow both, read and write operations, to be performed in your Cloud Firestore database. But this is not the reason why your RecylerView is empty. When you try to map a document from Firestore into an object of your "ModelClass", the name of the fields that exist in your class must match the name of your properties that exist in your database. Unfortunately, in your case, the fields don't match. See, the fields in your class start with lowercase, while in the database start with a capital letter, which is not correct.
To solve this, you have two options, you either change the name of your properties in the database to match the one in the class, or you can use an annotation in front of the getters. For example, if you have a field called "date" and the property in the database is called "Date" (upper-case D), your getter should look like this:
@PropertyName("Date")
public String getDate() {
return date;
}
In this way, you tell the compiler to look for a property called "Date" and not "date".
Because you are using public getters, don't also forget to set the fields in your class as private. If you want to keep them, for example, public, the getters are not needed. You can set the values directly on the public fields. So a minimum class declaration might look like this:
public class ModelClass {
public String date, time, text, divider;
}
Please also note, that the public no-argument constructor is also not needed, as it is provided by the compiler.
RecyclerView is not showing data from Firestore
I think the problem is that the listener is triggered after the adapter is created and set. You need to explicitly call myCompanyAdapter.notifyDataSetChanged
after the data list is modified.
Please try the below code
recyclerView = findViewById(R.id.companyFeed_RecyclerView_CompanyList);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ArrayList<Company> myCompanyData = new ArrayList<>();
CompanyAdapter myCompanyAdapter = new CompanyAdapter(myCompanyData, CompanyFeedActivity.this);
recyclerView.setAdapter(myCompanyAdapter);
myCompanyData.add(new Company("Company marc","trustworthy",null));
db.getFirestore().collection("companies").addSnapshotListener((value, error) -> {
assert value !=null;
for (QueryDocumentSnapshot snapshot : value) {
Company c = Deserialization.deserializeCompany(snapshot);
myCompanyData.add(new Company(c.getName(),c.getDescription(),null));
System.out.println("company: " + myCompanyData.get(1).getName());
}
myCompanyAdapter.notifyDataSetChanged()
});
android - how to display the array of object from Cloud FireStore in the RecyclerView
You need to two different classes. The first one would be, for example, ViewOrderModel
class, which will hold the fields as address
, currentTime
, documentID
, and so on.
And the second one called Product
:
class Product {
String documentID, productName;
int productPrice, totalPrice, totalQuantity;
}
Which will hold the properties corresponding to the object that exists in the itemList
. So your ViewOrderModel
class should look like this:
public class ViewOrderModel implements Serializable {
String userName,phoneNumber,currentTime,address,documentID,productName;
List<Product> itemList;
br>}
Firestore data doesn't show up in RecyclerView
You aren't getting anything from the database because the name of your fields inside the Upload
class are different than the name of the fields that exist in the database. Both should match. To solve this, you either change all the name of your fields inside your Upload
class to match the properties that exist in the database or your can use annotations. Because I see that you are using private fields and public getters, you should use the PropertyName annotation only in front of the getter, for instance your getName()
getter should look like this:
@PropertyName("name")
public String getName() {
return mName;
}
Related Topics
How to Read a Text File in Android
Get Nested Json Object With Gson Using Retrofit
Relation Between Memory Host and Memory Arguments Xms and Xmx from Java
Connect Java to a MySQL Database
Understanding Checked VS Unchecked Exceptions in Java
How to Concatenate Two Arrays in Java
How to Reverse an Int Array in Java
How to Generate an Md5 Hash in Java
What Is a Stringindexoutofboundsexception - How to Fix It
Java.Text.Parseexception: Unparseable Date: Java.Text.Dateformat.Parse(Dateformat.Java:579)
Why Do I Get "Failed to Bounce to Type" When I Turn Json from Firebase into Java Objects
How to Deal With Linkageerrors in Java
Why Am I Getting a Noclassdeffounderror in Java
Difference Between Chromedriver and Webdriver in Selenium