Home > Software engineering >  Passing data from cloud Firestore to ListView
Passing data from cloud Firestore to ListView

Time:04-21

I am trying to get my data from Cloud Firestore and pass it into the ListView. Currently, my code would need to pass the bus name into an ArrayList and it would pass to the ListView.

MainActivity.java

public class busTimetable extends AppCompatActivity {

private static final String TAG = "busTimetable";

FirebaseFirestore fStore;
private ListView lv;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.ongoing_bus);
    fStore = FirebaseFirestore.getInstance();

    lv = (ListView) findViewById(R.id.listView);
    lv.setEmptyView(findViewById(R.id.empty));
    //ArrayList<String> arrayList = new ArrayList<String>();
    
    foo(new Callback() {
        @Override
        public void myResponseCallback(ArrayList<String> result) {

            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
                    this,
                    android.R.layout.simple_list_item_1,
                    result);

            lv.setAdapter(arrayAdapter);
        }
    });

}

interface Callback {
    void myResponseCallback(ArrayList<String> result);//whatever your return type is: string, integer, etc.
}

public void foo(final Callback callback) {
    fStore.collection("drivers")
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot document : task.getResult()) {
                            String busName = document.getString("fName");
                            boolean ongoing = document.getBoolean("ongoing");
                            Log.d(TAG, "SUCCESSFULL GET USER DATA");
                            ArrayList<String> arrayList = new ArrayList<String>();

                            if (ongoing) {
                                arrayList.add(busName);
                                callback.myResponseCallback(arrayList);
                            }
                        }
                    }
                }
            });


}

}

ongoing_bus.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ListView
        android:id="@ id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@ id/empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/no_results" />

</LinearLayout>

Firestore Database Structure

Screenshot of my database structure

If I did not add in the code arrayList.add("busName");

My ListView will show no result, but when I add in the code, it will show the result of the code but with the text busName on top of it. I wish to display the bus name without the "busName" text.

here is the sample of expected output

CodePudding user response:

Have a look at the code below. The code in your onComplete method runs later in time, so when it runs you can add the data received to the adapter itself, not the array, which will automatically notify the ListView that it needs to update.


public class busTimetable extends AppCompatActivity {

    private static final String TAG = "busTimetable";

    FirebaseFirestore fStore;
    private ListView lv;
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ongoing_bus);
        fStore = FirebaseFirestore.getInstance();

        lv = (ListView) findViewById(R.id.listView);
        lv.setEmptyView(findViewById(R.id.empty));
        
        // Create an empty adapter - no items set yet
        adapter = new ArrayAdapter<String>(
                    this,
                    android.R.layout.simple_list_item_1);
        lv.setAdapter(adapter);
                    
        // call the async method - when it completes (some time in the future)
        // it will add stuff to the adapter
        fStore.collection("drivers")
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()) {
                        
                        ArrayList<String> arrayList = new ArrayList<String>();
                        for (QueryDocumentSnapshot document : task.getResult()) {
                            String busName = document.getString("fName");
                            boolean ongoing = document.getBoolean("ongoing");
                            Log.d(TAG, "SUCCESSFULL GET USER DATA");
                            
                            if (ongoing) {
                                arrayList.add(busName);
                            }
                        }
                        
                        adapter.clear();
                        adapter.addAll(arrayList);
                    }
                }
            });

        // This will always print "0" - it runs before the code above
        // in the onComplete callback
        Log.d(TAG, "Adapter size = "   adapter.getCount());
    }

CodePudding user response:

There is nothing in your code that indicates the addition of the "busName" inside your list, at position zero. However, if you refactor your code like below, you'll get the correct way of adding the list to the callback:

public void foo(final Callback callback) {
    fStore.collection("drivers")
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()) {
                        ArrayList<String> arrayList = new ArrayList<>();
                        for (QueryDocumentSnapshot document : task.getResult()) {
                            String busName = document.getString("fName");
                            boolean ongoing = document.getBoolean("ongoing");
                            Log.d(TAG, "SUCCESSFULL GET USER DATA");

                            if (ongoing) {
                                arrayList.add(busName);
                            }
                        }
                        callback.myResponseCallback(arrayList);
                    }
                }
            });

Things that are changed:

  • Got the creation of the ArrayList out of the loop. In this way, you'll create a single instance and not one at each iteration.
  • Got the addition of the ArrayList to callback out of the loop, from the exact same reasons.
  • Related