I'm totally new to Firebase and need to know how to check if my writing task was successful because if I don't, the MainActivity starts and messes up my Register progress.
This checks if Username is already taken and registers the user if it isn't:
Query usernamequery = myRef.orderByChild("Username").equalTo(Username);
usernamequery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
// TODO: handle the case where the data already exists
editText.setError("Username taken!");
return;
}
else {
// TODO: handle the case where the data does not yet exist
myRef.child("Users").child(Username).child("Userid").setValue(user.getUid());
myRef.child("Users").child(Username).child("Username").setValue(Username);
startActivity(maps);
finish();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(Username.this, "Error", Toast.LENGTH_LONG).show();
}
});
But I want the Intent to Main Activity (maps) only be fired when
myRef.child("Users").child(Username).child("Userid").setValue(user.getUid());
and the other one is finished with its task and is successful.
What can I do?
To know when a write operation has completed on the server, add a completion listener:
myRef.child("Users").child(Username).child("Userid").setValue(user.getUid(), new DatabaseReference.CompletionListener() {
void onComplete(DatabaseError error, DatabaseReference ref) {
System.err.println("Value was set. Error = "+error);
// Or: throw error.toException();
}
});
If there was an error, details will be in the error operation. If the write operation was completed without problems, the error will be null.
If you want to write to multiple locations with a single operation, you'll want to look at the update() method
The correct overload for setValue() is documented here.
Related
I am using addvalueEventListener function to fetch data from firebase. I am trying to achieve AND operation by using this function. Issue is that when I am calling this function, it can filter data client side and also show in recyclerview but it can run if statement if data found and also run else part.
Suppose I want data which is available in firebase, it filters the data and show and also run else part data not found.
My main function code is:
private void GetFilterData(final String filter) {
reference = FirebaseDatabase.getInstance().getReference().child("Donation");
Query query = reference.limitToLast(20).orderByChild("username").equalTo(username);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//Here I can check if data is exist or not, if exist it shows data
if (dataSnapshot.exists())
{
arrayList.clear();
alert.setVisibility(View.GONE);
for (DataSnapshot dataSnapshot1:dataSnapshot.getChildren())
{
DonationHelper donationHelper = dataSnapshot1.getValue(DonationHelper.class);
//here I want to check again and filter data, if data exist, shows data and if does not exist required filter then run else part. But issue is that if data exist it shows data and also run its else part.
if (donationHelper.getAction().equals(filter))
{
pd.cancel();
arrayList.add(donationHelper);
}
else
{
//Filter data exist or not, everytime it run else part code
pd.cancel();
alert.setVisibility(View.VISIBLE);
alert.setText("Currently no request is in Queue");
//Toast.makeText(Track_Donation.this, "No data found", Toast.LENGTH_SHORT).show();
}
adapter = new DonationAdapter(Track_Donation.this,arrayList);
donationdata.setAdapter(adapter);
}
}
else
{
pd.cancel();
alert.setText("Start do Donation, and help Poor and Needy people's");
Toasty.error(Track_Donation.this, "You don't do any Donation yet", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
pd.cancel();
Toasty.error(Track_Donation.this, "Server Error", Toast.LENGTH_SHORT).show();
}
});
}
How i can in this code
#Override
protected void onStart() {
super.onStart();
//if the user is already signed in
//we will close this activity
//and take the user to profile activity
if (mAuth.getCurrentUser() != null) {
finish();
startActivity(new Intent(this, ActivitySplash.class));
}
}
make check whether the child (userId) is set to ON / OFF and if ON then we run the code
if (mAuth.getCurrentUser() != null) {
finish();
startActivity(new Intent(this, ActivitySplash.class));
}
if OFF then we show a specific activity.
My database
As #FrankvanPuffelen said, you should spend some time reading docs, it would help you write code yourself, still I am briefing the things for you here. It should make things more clear.
Reading from database is done by correctly referencing your desired node from the database and then using the correct eventListener. There are 3 types of eventListeners present, singleValueEventListener, valueEventListener and childEventListener.
Read more about each of them in detail in docs.
This answer can also help you understand childEventListeners.
To retrieve the value of status node you have to go sequentially through your database parent nodes, that are users and that uid with value nfe....
So in code it would look something like this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("users").child(uid);
// uid has the value nfe...
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String status = dataSnapshot.child("status").getValue(String.class);
// compare the value of status here and do what you want
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d(TAG, "onCancelled", databaseError.toException());
}
});
Android beginner here. This may sound very silly, but I'm having issues with an if-else block that I created in my onDataChange() method in an event listener for a firebase database-reference.
Here's the code for the listener:
requestRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot request : dataSnapshot.getChildren()){
RequestDetails retrievedDetails = request.getValue(RequestDetails.class);
if(retrievedDetails.equals(requestDetails)){
alreadyRequested = true;
// finish();
// startActivity(getIntent());
break;
}
}
}
if(!alreadyRequested){
//alreadyDisplayed = true;
mDatabase.child("Requests").push().setValue(requestDetailsHashMap);
Toast.makeText(ParticipantSportOptions.this, "Request Successfully Sent!", Toast.LENGTH_SHORT).show();
// finish();
// startActivity(getIntent());
}
else if(alreadyRequested){
Toast.makeText(ParticipantSportOptions.this, "Request has already been received!\nPlease wait for approval!",
Toast.LENGTH_SHORT).show();
return;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
This listener is inside the overridden method onClick() for a button.
What needs to happen is this - the first time this button is clicked, data (a request) is written into the database. For every subsequent click of the button, I check if the user is attempting to send multiple requests and if so I display the toast and return.
What I observe during run-time is that on the first click of the button, both toast messages are displayed.
Why does this happen?
As said by the_noob it can be fixed by using addListenerForSingleValueEvent()
This is my code for reading Firebase data:
final String[] booknum = {"0"};
databaseReference.child("All BID").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
booknum[0] =Long.toString(snapshot.getChildrenCount());
Toast.makeText(getApplicationContext(), booknum[0],Toast.LENGTH_LONG).show();
}
#Override public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
Toast.makeText(getApplicationContext(), booknum[0],Toast.LENGTH_LONG).show();
When I am executing this, the first toast(inside ValueEventListener) prints the right answer (eg '8'). But the toast outside always prints 0 no matter what.
Please Help!
The ValueEventListener is asynchronous. The lines of code inside of the listener, including the assignment of booknum[0], are not guaranteed to execute before the lines of code written outside of the listener. If you depend on the new value of booknum[0] for some operation, consider moving that operation inside of onDataChange() to ensure it uses the new value.
I know this might be a common question but I am really stuck at this point.
I am receiving data from 2 multiple locations and after I received from both I need to continue executing and than return that data to the calling method.
I am aware of this thread: https://stackoverflow.com/a/33204705/1820644 but it doesn't fit here actually as I need to return the data to the calling method.
For the method that blocks UI thread I can call it from AsyncTask, there is no problem. But how can I return data to the calling method that I have successfully completed execution.
This is inside my helper class
// This method should be called in AsyncTask
public boolean doComputation() {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("activity")
.child(id);
ref.child("path1").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Call 1 completed
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
ref.child("path2").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Call 2 completed
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// Some more to do
// Need to return true after execution complete
return true;
}
I can not return true inside of the onDataChange as it will counted for onDataChange method and not for doComputation.
I can perform the calculation by moving it to another method and after each onDataChange callback I can check for variable count, and if it is 2 I can perform the calculations. But after it completes I need to notify it to the calling method that execution is completed.
This is a little bit tricky with Firebase. But, I am really stuck at it right now. Any help will be much appreciated. Thank you.
I have gone with the Tasks API which Firebase uses already. Its great.
As mentioned by #qbix , This answer does the same thing. The example in the answer explains good.
You can also find video link of this API instructions here.
I have tried and tested it. Solves my problem.
Depends on the case, what I usually do is to set a flag after each listener completed its job and then call a method to check the flags. If they are all completed, then do the next operation.
For example
private Boolean listener1Completed;
private Boolean listener2Completed;
public void addListeners() {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("activity")
.child(id);
ref.child("path1").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener1Completed = true;
checkListenerStatus();
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
ref.child("path2").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener2Completed = true;
checkListenerStatus();
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
private void checkListenerStatus() {
if (listener1Completed && listener2Completed) {
// do computation
}
}
Since firebase works in another thread you can't return desired result instantly. You have to create callback to notify the caller when your result already received. You can achieve this using interface read here
Another way. You can get result from Asynctask
Return a value from AsyncTask in Android
Or you can pass your class in parameter (not in AsyncTask job)
public void doComputation(yourCallerClass cls) {
//firebase result.....void
cls.YourResult(trueOrFalse);
.....
}
in your caller class instance eg. yourCallerClass
...
public void YourResult(boolean result){
// do stuff
}