Coding Noobie Coding Noobie - 3 months ago 23
Android Question

Call method in another thread on completion

Currently, I am using firebase Realtime Database. Hence, my data changes come from another thread. Hence, I have no control on when the fresh data update comes over. How do I then know when to call to refresh my UI?

This is my implementation of a swipe to delete in a RecyclerView.

public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int pos = viewHolder.getAdapterPosition();
mListRoute.get(pos).removeRoute();
refreshUI();
}


This is the removeRoute() method found in my Route class

public void removeRoute() {
//Delete all the Route Instructions
DatabaseReference mRef = FirebaseDatabase.getInstance().getReference()
.child("Routes")
.child(routeId)
.child("Route Instructions");

mRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot routeInstruc : dataSnapshot.getChildren()) {
routeInstruc.getValue(RouteInstructions.class)
.removeRouteInstructions();
}

DatabaseReference mRef2 = FirebaseDatabase.getInstance().getReference()
.child("Routes")
.child(routeId);
mRef2.removeValue();
}

@Override
public void onCancelled(DatabaseError databaseError) {

}
});
}


As you can see, the onDataChange() is called by another thread. Which means i do not know when to call my refreshUI() method.

I think i might be able to use a Looper but how do i fit that in the Route class?

Thanks

Answer

What you are looking for are callbacks.

Callbacks are practically mandatory when dealing with asynchronous calls, because when you call an asynchronous task, you are basically asking a worker thread to work for you.
It may take 1 second, 10 seconds, 10 minutes, etc, and you can not know for sure. What you can do is delegate that same worker thread and tell her "hey, reply back when you finish the task I gave you".
Enter the callbacks!

You can check for more documentation regarding callbacks here

Say that you have your query defined with the ValueEventListener

query.addListenerForSingleValueEvent(new ValueEventListener() {
   @Override
   public void onDataChange(DataSnapshot data) {

   }
}

What you should do is have a callback method that replies back as soon as the query listener returns a value (in other words, when your query is executed). So, have a method like 'onResponseReceivedFromFirebase' and implement it on the callback

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // Implement your callback here with the parameters you want (for instance, I used a String there)
    public void onResponseReceivedFromFirebase(String argument){
        Log.d(MyActivity.class,argument);
    }

    ....

    query.addListenerForSingleValueEvent(new ValueEventListener() {
       @Override
       public void onDataChange(DataSnapshot data) {
            onResponseReceivedFromFirebase("the response arrived!");
       }
    }

    ...

}

@Edit Base on your updated code, I would proceed with the following

@Override
public void onDataChange(DataSnapshot dataSnapshot) {
    for (DataSnapshot routeInstruc : dataSnapshot.getChildren()) {
         routeInstruc.getValue(RouteInstructions.class)
        .removeRouteInstructions();
    }
    DatabaseReference mRef2 = FirebaseDatabase.getInstance().getReference()
                    .child("Routes")
                    .child(routeId);
            mRef2.removeValue();
   // Implement the callback here 
   MyActivity.this.onResponseReceivedFromFirebase("We have received a response from   dataChanged");
}