1

I am trying to figure out how to do something with data returned from an AsyncTask.

I have an activity where I am calling an async Firebase get operation (operation existing in a different class), and I want to update an TextView existing in the Activity with the size of the ArrayList retrieved. Here is my Firebase call that get's called in Activity onCreate:

public void getAttendants() {

   ArrayList<AttendModel> attendees = new ArrayList<AttendModel>();
    FirebaseConnection.getInstance().getAllAttendeesFor(uuid, attendees);

    Log.d("attendees", String.valueOf(attendees.size()));
}

and here is my Firebase operation :

 public void getAllAttendeesFor(String UUID, final ArrayList<AttendModel> attendArray) {
    final DatabaseReference attendObjects = getDatabaseTableWith(Constants.tableAttendObject);

    Query queryRef = attendObjects.orderByChild(Constants.taAttendObjectUUID).equalTo(UUID);

    queryRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
                HashMap<String, Object> attend = (HashMap<String, Object>) postSnapshot.getValue();
                String UUID = (String) attend.get(Constants.taAttendObjectUUID);
                String userUsername = (String) attend.get(Constants.AttendObjectUserUsername);

                AttendModel attendModel = new AttendModel(userUsername, UUID);
                attendArray.add(attendModel);

 //here would like to notify or somehow return the attendArray
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

}

What is the best approach of this in Android? Is there the possibility to implement an Adapter of sorts or a completion handler?

AL.
  • 36,815
  • 10
  • 142
  • 281
anho
  • 1,705
  • 2
  • 20
  • 38
  • `ValueEventListener.onDataChange` *is* a completion handler. Have you considered updating the text view from within that? – Frank van Puffelen Feb 08 '17 at 19:19
  • I did, but at the moment I am having a class where I am doing all my Firebase operations and would like to have an elegant way to return the value in a way back to the class that is it called for (this way I eliminate code redundancy in other classes that I would maybe need to perform the same operation) – anho Feb 08 '17 at 19:21
  • is there a way that I can create a completion handler myself for my function that will be called in the `onDataChange` ? – anho Feb 08 '17 at 19:22
  • You could create an interface and pass that into the method where you are doing the Firebase operations, then call back to your own `onDataChange` in that when Firebase retrieves your data – Andrew Brooke Feb 08 '17 at 19:27
  • hmm, this sounds interesting, I will check it out and come back with a solution I hope ... thanks – anho Feb 08 '17 at 19:31

1 Answers1

3

What you are looking for is Callback interface, as for your needs you need simple interface that implement single method with single parameter, as there is no out of the box convention for Java 6 (Android Java version) you can easily create it by yourself:

interface Callback {

void act(List<AttendModel> models);
}

pass it as an argument to the firebase wrapping method, and call it with the result.

public void getAllAttendeesFor(String UUID, final ArrayList<AttendModel> attendArray, final Callback callback) {
    final DatabaseReference attendObjects = getDatabaseTableWith(Constants.tableAttendObject);

    Query queryRef = attendObjects.orderByChild(Constants.taAttendObjectUUID).equalTo(UUID);

    queryRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
                HashMap<String, Object> attend = (HashMap<String, Object>) postSnapshot.getValue();
                String UUID = (String) attend.get(Constants.AttendObjectUUID);
                String userUsername = (String) attend.get(Constants.AttendObjectUserUsername);

                AttendModel attendModel = new AttendModel(userUsername, UUID);
                attendArray.add(attendModel);

                callback.act(attendArray)
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

}

then in your upper level method:

public void getAttendants() {

   ArrayList<AttendModel> attendees = new ArrayList<AttendModel>();
    FirebaseConnection.getInstance().getAllAttendeesFor(uuid, attendees, 
        new Callable<List<AttendModel) {
          void act(List<AttendModel> attendees){
            //here you can update the UI
            Log.d("attendees", String.valueOf(attendees.size()));
          }
        };


}

Just be aware that you can update the UI only if onDataChange method of the firebase query is called on the main thread.

yosriz
  • 10,147
  • 2
  • 24
  • 38
  • 1
    "you can update the UI only if onDataChange method of the firebase query is called on the main thread" It is. – Frank van Puffelen Feb 08 '17 at 19:36
  • @yosriz how about if I need the first look-up to populate two additional lookups in Firebase? I have a question opened here: https://stackoverflow.com/questions/68553544/completion-handler-or-equivalent-in-android – Learn2Code Jul 29 '21 at 15:10