How to use adapters to display firestore collections in Android ListView
I’m working on a simple application where I need to see every document in a specific FirebaseFirestore
collection in my application.
To get this done, I think the best solution is to use a ListView
with a custom ArrayAdapter
. And converted the Firestore document into a custom Java class I created.
My document is set to:
(string) Title:
(Date) Due Date:
(Number) exp :
(string) description:
However, something seems to be not working in my logic. Below is the code for my process:
Task .java:
public class Missions {
private String title;
private Number exp;
private String date;
private String description;
public Missions() {}
public Missions(String title, Number exp, String date, String description) {
this.title = title;
this.exp = exp;
this.date = date;
this.description = description;
}
public String getTitle(){
return title;
}
public Number getExp(){
return exp;
}
public String getDate(){
return date;
}
public String getDescription(){
return description;
}
}
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private final String COLLECTION_KEY = "missions";
Views
private TextView mHeaderView;
private ListView mMissionListView;
Firebase
private FirebaseFirestore db;
Adapter
private MissionsAdapter mMissionAdapter;
private ArrayList<Missions> mMissionsList;
@Override
protected void onCreate(Bundle savedInstanceState){
/*
* My code here deals with authentication
*
*/
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHeaderView = (TextView) findViewById(R.id.missionHeader);
mMissionsListView = (ListView) findViewById(R.id.missionList);
mHeaderView.setText("Available Missions"));
get Database
db = FirebaseFirestore.getInstance();
Set up the ArrayList
mMissionsList = new ArrayList<Missions>();
set the Adapter
mMissionAdapter = new MissionsAdapter(this, mMissionsList);
mMissionListView.setAdapter(mMissionAdapter);
db.collection(COLLECTION_KEY).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()){
for(QueryDocumentSnapshot document : task.getResult()){
Log.d("MissionActivity", document.getId() + " => " + document.getData());
Missions miss = document.toObject(Missions.class);
mMissionsList.add(miss);
}
}
else {
Log.d("MissionActivity", "Error getting documents: ", task.getException());
}
}
});
add the whole Arraylist of MIssions to the adapter
mMissionAdapter.addAll(mMissionsList);
}
}
MissionsAdapter.java
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
public class MissionsAdapter extends ArrayAdapter<Missions> {
public MissionsAdapter(Context context, List<Missions> object){
super(context,0, object);
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
convertView = ((Activity)getContext()).getLayoutInflater().inflate(R.layout.item_mission,parent,false);
}
TextView titleTextView = (TextView) convertView.findViewById(R.id.mission_title);
TextView expTextView = (TextView) convertView.findViewById(R.id.mission_exp);
TextView dateTextView = (TextView) convertView.findViewById(R.id.mission_date);
TextView descriptionTextView = (TextView) convertView.findViewById(R.id.mission_description);
Missions mission = getItem(position);
titleTextView.setText(mission.getTitle());
expTextView.setText(mission.getExp().toString());
dateTextView.setText(mission.getDate());
descriptionTextView.setText(mission.getDescription());
return convertView;
}
}
item_missions.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:id="@+id/mission_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="@color/input_login"
android:hint="There will be a title"/>
<TextView
android:id="@+id/mission_exp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textAppearance="?android:textAppearance"
android:textColor="@color/input_login"
android:hint="There will be exp"/>
<TextView
android:id="@+id/mission_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textAppearance="?android:textAppearance"
android:textColor="@color/input_login"
android:hint="There will be a date"/>
<TextView
android:id="@+id/mission_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textAppearance="?android:textAppearance"
android:textColor="@color/input_login"
android:hint="There will be a description"/>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/missionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Edit/Create mission"
android:gravity="center"
android:textStyle="bold"
android:textColor="@android:color/black"
android:textAllCaps="true"
android:textSize="30dp"
android:paddingTop="20dp"
/>
<ListView
android:id="@+id/missionList"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
Any comment will help.
Solution
You’re almost there. The problem in your code is that you are trying to fill the adapter with an empty list because you have not finished getting data from the database when you do this. Note that the onComplete()
method has asynchronous behavior. To resolve this issue, use the following code:
db.collection(COLLECTION_KEY).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
List<Missions> mMissionsList = new ArrayList<>();
if(task.isSuccessful()){
for(QueryDocumentSnapshot document : task.getResult()) {
Missions miss = document.toObject(Missions.class);
mMissionsList.add(miss);
}
ListView mMissionsListView = (ListView) findViewById(R.id.missionList);
MissionsAdapter mMissionAdapter = new MissionsAdapter(this, mMissionsList);
mMissionsListView.setAdapter(mMissionAdapter);
} else {
Log.d("MissionActivity", "Error getting documents: ", task.getException());
}
}
});
As you can see, I have declared and used the adapter in the method.