Java – How to use adapters to display firestore collections in Android ListView

How to use adapters to display firestore collections in Android ListView… here is a solution to the problem.

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.

Related Problems and Solutions