Firebase Android read data -> processing->update data "Global variable problem" - java

I have to take data from Firebase and remove delete some value and then save the data to Firebase. Here is my read function in my Activity:
private void readData() {
mAuth = FirebaseAuth.getInstance();
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference().child("users");
DatabaseReference currentUserDB = mDatabase.child(mAuth.getCurrentUser().getUid());
currentUserDB.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Map<String,Object> map = (Map)dataSnapshot.getValue();
kwotaKonta= ((String)map.get("account"));
When I make everything in "onDataChange" it's removed over and over so
I tried to create global variable named "kwotaKonta" and make it onCreate but when function is over "kwotaKonta" is null. How can I get the value from onDataChange?
Thx!

its remove over and over
This is happening because you are using addValueEventListener instead of addListenerForSingleValueEvent. The ValueEventListener is triggered every time something changes in your database. So if you remove something from the database, your onDataChange() method fires again.
To solve this, please change:
currentUserDB.addValueEventListener(/* ... */);
to
currentUserDB.addListenerForSingleValueEvent(/* ... */);
From the official documentation pelase see:
addListenerForSingleValueEvent(ValueEventListener listener) - Add a listener for a single change in the data at this location.
and
addValueEventListener(ValueEventListener listener) - Add a listener for changes in the data at this location.

Related

How to update entry in Firebase Database based on an attribute value

I am using the Firebase Realtime Database with Android in Java. I have the following database screenshot:
I would like to change the availability value (from 0 to 1) for the ingredient with the attribute "ingredient_name = Lime". The attribute ingredient_name is actually something like a primary key meaning that there will be no other database entry with this specific name.
I tried the following code
DatabaseReference rootRef;
rootRef = FirebaseDatabase.getInstance("https://....app").getReference();
String ingredientToBeUpdate = "Lime";
rootRef.child("ingredients").orderByChild("ingredient_name").equalTo(ingredientToBeUpdate).child("availability").setValue(1);
But I get the error "Cannot resolve method 'child' in 'Query'". Can you tell me how to do this update properly? So I would like to update the value from the database entries who attribute "ingredient_name" is equal to a certain string ingredientToBeUpdate.
Firebase doesn't support so-called update queries, where you send a condition and the new data to the database and it them writes the new data for all nodes matching the condition.
Instead you will need to execute the query in your application code, loop through the results, and update each of them in turn:
rootRef
.child("ingredients")
.orderByChild("ingredient_name")
.equalTo(ingredientToBeUpdate)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ingredientSnapshot: dataSnapshot.getChildren()) {
ingredientSnapshot.getRef().child("availability").setValue(1);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}
Also see:
Firebase Android, set value where x = x?
Is it possible to update a specific child's value without ID or key in firebase realtime database from android on button click?

Firebase DataSnapshot.getValue() is null

I've been looking at the other errors here in SO, in regards to mine and still can't seem to get anywhere, since I keep getting the DataSnapshot.getValue() returning null...
First I get the db-ref:
private DatabaseReference f_database = FirebaseDatabase.getInstance().getReference().child("maps_data");
Then in my OnCreate method inside my activity I've added a listener:
f_database.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){ <<<< Problem is here, value is null
for(DataSnapshot snapshot:dataSnapshot.getChildren()){
double lati = 0;
// Get UsersLocationFavorites object and use the values to update the UI
UsersLocationFavorites userLocFav = snapshot.getValue(UsersLocationFavorites.class);
LatLng location = new LatLng(userLocFav.getFavoriteSpot().getLatitude(), userLocFav.getFavoriteSpot().getLongitude());
gmap.addMarker(new MarkerOptions().position(location).title("Old Marker"));
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
And looking inside my firebase database, I have the following:
I've double checked spellings ("maps_data"), I've looked an many SO-problems here, where I can't find one that fits my problem.
Can anyone see, what I've done wrong?
You're mixing up the databases provided by Firebase.
All the code you're showing is accessing Firebase Realtime Database. But the screenshot is showing data in Firestore. These are completely diffrent database products. If you want to read data out of Firestore, you should be using the Firestore SDK instead.

Retrieve Node ID from FireBase Database on CardView Click

I have a firebase database I am using with Android.
To Retrieve and show data from Firebase, I am using FirebaseRecyclerAdapter and results are displayed to CardView.
Now I am getting all listings from my required table to CardView. Every Node has an automatically generated value as shown in the image below.
How do I retrieve this value in Android when I click on respective CardView. I'll need this value for further database operations.
Now, I tried some of the methods posted here as well as online forums but nothing seems to work. I am not asking for complete code, just how to do it? Some reference code would be great.
Regards
To get the node id try the following:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("Projects");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage());
}
};
query.addListenerForSingleValueEvent(valueEventListener);
First, add a reference to node Projects then loop inside of it and retrieve the id using getKey().

Firebase - retrieving data by value to an outside variable

I have a question regarding Firebase Realtime database.
I'm trying to do a bookmark option in my program, which allows the user to store his/her's favourite pages, however whenever I try to retrieve data from my firebase database, the data is restored after the method returns a value.
public static boolean checkIfBookmarked(final String title){
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final DatabaseReference userBookmarks = FirebaseDatabase.getInstance().getReference().child("users")
.child(user.getUid()).child("bookmarks");
final boolean[] exists = new boolean[1];
userBookmarks.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
exists[0] = dataSnapshot.child(title).exists() ;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return exists[0];
}
Firebase use callback methods to get the data from the server, In your case the return statement will be executed before the callback come from the Firbase. You can try to pass a callback method to your function and execute that when the callback from Firebase is triggered.
public static void checkIfBookmarked(final String title, callbackFunction){
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final DatabaseReference userBookmarks = FirebaseDatabase.getInstance().getReference().child("users")
.child(user.getUid()).child("bookmarks");
final boolean[] exists = new boolean[1];
userBookmarks.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
exists[0] = dataSnapshot.child(title).exists() ;
//execute your callback function here
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return;
}
Check this to see how to pass a function as parameter.
Passing function as a parameter in java
An alternative would be to move your code into OnDataChange method
You cannot return something now that hasn't been loaded yet. With other words, you cannot simply return the first element of your array exists[0], outside the onDataChange() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to use that result outside that method, the data hasn't finished loading yet from the database and that's why is not accessible.
A quick solve for this problem would be to use exists[0] only inside the onDataChange() method, or if you want to use it outside, I recommend you dive into the asynchronous world and see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Reading a value from a specific userid child node in database

I know this has been asked 100 times already but none of the solutions seem to be working for me.
Want to read the database of "user_preferences" for the user that is signed in (userID) and read the gender/age/weight/height values and store them in the variables shown below. currently returns null on everything (the log statement and the values). Feel like i havent got the path set up properly or something. help would be great!
and my code
mAuth = FirebaseAuth.getInstance();
mFirebaseDatabase = FirebaseDatabase.getInstance();
myRef = mFirebaseDatabase.getReference();
userID = mAuth.getCurrentUser().getUid();
DatabaseReference testRef = myRef.child("user_preferences");
testRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) { //loop through the firebase nodes
UserPreferences userPreferences = new UserPreferences();
userPreferences.setAge(ds.child(userID).getValue(UserPreferences.class).getAge());
userPreferences.setHeight(ds.child(userID).getValue(UserPreferences.class).getHeight());
userPreferences.setWeight(ds.child(userID).getValue(UserPreferences.class).getWeight());
userPreferences.setGender(ds.child(userID).getValue(UserPreferences.class).getGender());
genderSet = userPreferences.getGender();
age = userPreferences.getAge();
height = userPreferences.getHeight();
weight = userPreferences.getWeight();
Log.d(TAG, "onDataChange: " + genderSet);
//
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
These two lines of code:
DatabaseReference testRef = myRef.child("user_preferences");
testRef.addValueEventListener(...)
are effectively querying the entire node called user_preferences. That means everything at that location - all users. It sounds like this is not what you want. If you want to query just a single user, you should be specific about that in your query by adding the userID that you want to the query location:
DatabaseReference testRef = myRef.child("user_preferences").child(userID);
testRef.addValueEventListener(...)
Also, these lines of code are confusing to me:
userPreferences.setAge(ds.child(userID).getValue(UserPreferences.class).getAge());
userPreferences.setHeight(ds.child(userID).getValue(UserPreferences.class).getHeight());
userPreferences.setWeight(ds.child(userID).getValue(UserPreferences.class).getWeight());
userPreferences.setGender(ds.child(userID).getValue(UserPreferences.class).getGender());
You're deserializing a UserPreferences object for each and every field you want to populate, which is wasteful. It seems to me that you really just want to deserialize it once and remember the object:
UserPreferences userPreferences = dataSnapshot.getValue(UserPreferences.class);
Regarding the null values, you seem to be using external fields, which will not be set until the Firebase returns the network call after at least a second. Your values will be null in the meantime, so you should not be setting them onto a UI element outside of onDataChange.
Also, you have a lot of gets/sets going on, when you only need to call one getValue() for the class, then additional ones for the fields.
Then, you don't seem to want to loop over anything, so you should directly access the user node from the top reference.
For example,
mAuth = FirebaseAuth.getInstance();
mFirebaseDatabase = FirebaseDatabase.getInstance();
myRef = mFirebaseDatabase.getReference();
userID = mAuth.getCurrentUser().getUid();
DatabaseReference testRef = myRef.child("user_preferences/"+userID);
// or .child("user_preferences").child(userID)
testRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserPreferences userPreferences = dataSnapshot.getValue(UserPreferences.class);
Log.d(TAG, "onDataChange: " + userPreferences.getGender());
// TODO: Update some UI element here
}
#Override
public void onCancelled(DatabaseError databaseError) {
// TODO: Add error handling
}
});
}
If you only want to read the values once, use testRef.addListenerForSingleValueEvent()

Categories