Reputation: 941
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
Upvotes: 0
Views: 921
Reputation: 1818
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");
}
@Edit 2 : On Frank van Puffelen's remark, the onDataChange method already runs on the Main Thread, thus allowing you to change any element on the UI.
Very import : If the processing payload of the outcoming data is considerably large, you should pass that same processing into another thread (e.g. An AsyncTask) to avoid making your app non-responsive.
Upvotes: 1
Reputation: 598728
While the Firebase client handles all network and disk IO on a separate thread, it invokes the callback to your code on the main thread. So you can update the UI straight from onDataChange()
, without having to worry about the thread yourself.
In fact, all examples in the Firebase documentation update the UI from their onDataChange()
(or onChild...()
) callbacks. One example from the database quickstart:
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Post post = dataSnapshot.getValue(Post.class);
mAuthorView.setText(post.author);
mTitleView.setText(post.title);
mBodyView.setText(post.body);
}
Upvotes: 2