Reputation: 1622
I am fairly new to Android/Java/Firebase so may be on the wrong track here, feel free to steer me in any direction...
I am trying to understand simply how to "do something" after an event handler has completed its job....
Specifically, I am trying to "cleanly" enscapulate firebase object management. I have a local object (User, for this example) that contains user data. A subset(subclass) of the user data is stored on Firebase. That is to say the balance of the User Object Data is stored only locally, because I can either calculate it an runtime, or otherwise it is not reasonable or required to store that data on Firebase. (This detail I think is irrelevant to the actual question)
The subclass (UserFireBase) is designed so it can be directly read to/from Firebase in one line using the buit in JSON Serialiser. Example below:
public Class User{
String UserID
Image userPhoto; //example of locally held User data
Boolean dataReadComplete=false;//a very poor locking device
public Class UserFirebase {//User Data stored on a Firebase Node
String UserName
String UserWebsiteURL
}
public void writeUserDatatoFB(){
refUserTree = new Firebase(FIREBASE_URL + "Users");
refUserTree.child(UserID).setValue(UserFirebase);//this works just fine
}
public void readUserDataFromFB(){
refUserTree = new Firebase(FIREBASE_URL + "Users");
dataReadComplete=false;
refUserTree.child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserFirebase = dataSnapshot.getValue(UserFirebase.class);
dataReadComplete=true;
}
@Override
public void onCancelled(FirebaseError firebaseError) {}});
So this does work, from the main activity I can effectively go:
user.readUserDataFromFB();
//wait until dataReadComplete=true, then do some stuff
user.writeDataToFB();
But it just seems wrong, and ugly design. i.e what is the Best Practice to have code execute after a one-time event handler is complete? e.g in other languages I might be able to pass in a method-as-a-parameter to the WriteUserData function, so that when it is finished, it calls the next bit of code I need to execute...
The only other solution I can currently think of is to move the WriteUserData code into my main activity, which also seems kind of ugly, not-encapsulated.
Is my general design utterly wrong here? I am not at all well acquainted with event driven programming.
(thankyou)
Upvotes: 0
Views: 1273
Reputation: 598765
Java supports callbacks too. In fact, that ValueEventListener
you're passing in is a form of callback. So if you want to execute the write operation after the data has loaded:
user.readUserDataFromFirebase(new Runnable() {
public void run() {
user.writeDataToFirebase();
}
});
public void readUserDataFromFirebase(Runnable onLoaded){
refUserTree = new Firebase(FIREBASE_URL + "Users");
refUserTree.child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserFirebase = dataSnapshot.getValue(UserFirebase.class);
onLoaded.run();
}
@Override
public void onCancelled(FirebaseError firebaseError) {}
});
};
It feels pretty non-OO this way, so I'd just make them static functions and pass the user in:
readUserDataFromFirebase(new UnaryOperator<UserFirebase>() {
public UserFirebase apply(UserFirebase user) {
user.writeDataToFirebase();
}
});
public static void readUserDataFromFirebase(String userID, UnaryOperator<UserFirebase> onLoaded){
refUserTree = new Firebase(FIREBASE_URL + "Users");
refUserTree.child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserFirebase user = dataSnapshot.getValue(UserFirebase.class);
onLoaded.apply(user);
}
@Override
public void onCancelled(FirebaseError firebaseError) {}
});
};
You could also look into Future
s, which are the Java class that deals with asynchronous loading situations such as this one. They're the Java equivalent to the JavaScript Promises that are getting much use these days.
Upvotes: 2