One of my routines in my main activity's onCreate() method is to communicate with the Firebase database to do one of three things:
1) If the user is a returning user, update all of their preferences on Firebase stored using SharedPreferences locally.
2) If the user is new and has no data stored on the cloud (they've never downloaded the app), do nothing.
3) If the user is new but has preferences stored under their unique Facebook profile ID, download their preferences and apply them to the SharedPreferences instance.
I must be missing some key, probably basic, piece of insight into how DataSnapshot works, because I can't get my following code to work:
private void initializeFirebase(){
my_db = FirebaseDatabase.getInstance();
DatabaseReference my_ref = my_db.getReference();
Map<String, ?> values = sharedPreferences.getAll();
if (values.isEmpty()){
final String id = Profile.getCurrentProfile().getId();
my_ref = my_ref.child("userid");
my_ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.getKey().equals(id)){
data = (Map<String, Object>)dataSnapshot.getValue();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
else {
for (Map.Entry<String, ?> entry : values.entrySet()) {
my_ref.child("userid").child(Profile.getCurrentProfile().
getId()).child(entry.getKey()).setValue(entry);
}
}
}
data is a global Map variable that is always null after getValue() is executed.
My JSON tree is organized as: root -> users -> userid -> each preference as a child node to the userid node. Any help would be appreciated!!
According to the API docs for getValue(), it can return null:
The data contained in this snapshot as native types or null if there is no data at this location.
So, the location you're querying has no data.
I'm going to guess that you didn't want to hard code a value of "userid" in your reference. I bet you mean to use the user's id from the previous line:
final String id = Profile.getCurrentProfile().getId();
my_ref = my_ref.child(id); // id instead of "userid"
Related
I'm new to Android development and Firebase. I am making an app in Java.
I've used Firebase Auth for sign-in and sign-up of a user. There are other variables I want to associate with each user (e.g. max squat, it's a fitness app) however, I saw a YT video that said you cannot do this with Firebase Auth. I will need to create a second array/ database to store this user information...if I were to use Firebase DB am I able to easily reference the variables/info stored for my methods?..e.g. If a user's max squat is stored can I easily reference it/assign it to a local variable so I could calculate how many reps they should do? Finally, if the user signs in using Firebase Auth, how do I link this with their info/variables stored in Firebase DB?
Apologies if my use of proper terminologies is lacking, as I said I'm relatively new.
Thanks
Firebase Auth is used only for users to SignIn and SignUp. You should continue using Firebase Auth for that part of your application. There is something called Uid and this is created during registration of a user with Firebase Auth. You can get this with (if user is logged in):
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String uid = user.getUid();
Then you can use this uid as an ID for your database item. When creating a new user in Firebase Realtime Database. Let's say you have a Model class named User.class.
public class User {
public String username;
public String email;
public int squats;
...
...
public User() { //Default constructor required for calls to DataSnapshot.getValue(User.class)
public User(String username, String email) {
this.username = username;
this.email = email;
}
And so on, you need getters and setters I guess you know that part. Then you can do this:
User user = new User(username, email);
user.setSquats(10);
...
...
//Add all data you need to add
Then you can set this value to Database under "users" reference which you need to create earlier like this:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(user);
This will create a new child under "users" inside Realtime database with all the values you have inside User.class. If you want to get those values back, just use this:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference databaseUsers = database.child("users");
User myUser = null;
Query usersQuery = databaseUsers.orderByChild("username").equalTo(uid); //you can use any value to order as you want, or you don't have to, there is many options for this query
usersQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChanged(#NonNull DataSnapshot snapshot) {
try {
for (DataSnapshot user : snapshot.getChildren()) {
myUser = user.getValue(User.class);
}
} catch (Exception e) {
e.printStackTrace();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
I am new to android programming and wish to explore more on Android programming. My current database tree looks like this and this is how I push the data into the database .
Can any professional teach me on how to retrieve a specific data (e.g. name / phone number) from a specific user in the user list and display them?
Thanks in advance!
Update:
After trying several solutions, the only code that can retrieve the name is this
databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child("-MA5f3qb0nBBTkViv-pz");
I even tried to assign the UID to a string and put in into the second child like this
String UID = firebaseAuth.getCurrentUser().getUid();
But the code will not run too with the error of "Attempt to invoke virtual method on a null object reference".
To retrieve information try the following:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("User");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User userInfo = dataSnapshot.getValue(User.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
Add a reference to node User and then using addListenerForSingleValueEvent you can retrieve the values.
I'm having some trouble deleting nodes in Firebase
This is how I upload my data
BigBoy add = new BigBoy(addCate);
myRef.push().setValue(add);
This is how i'm trying to delete my data
databaseReference = FirebaseDatabase.getInstance().getReference().child("message");
myRef = database.getReference("message");
String sfasf = Utils.object.getSfasf();
DatabaseReference remove = FirebaseDatabase.getInstance().getReference("message").child(sfasf);
remove.removeValue();
But the problem is that the node is not being deleted.
Make your firebase call like this -
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("message");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
if (dataSnapshots.child("sfasf").exists()) {
dataSnapshots.child("sfasf").removeValue();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
1) You have a reference object but you dont use it. You have created 2 variable references and you dont use them.
2) Your code is wrong in order to remove the node you must specify the key
myRef = database.getReference("message");
myRef.child(key).remove();
---edit---
try this
myRef.child(key).removeValue();
---edit---
From the official documentation:
The simplest way to delete data is to call removeValue() on a reference to the location of that data. You can also delete by specifying null as the value for another write operation such as setValue() or updateChildren(). You can use this technique with updateChildren() to delete multiple children in a single API call.
The problem was that I wasn't referencing the pushID when I was referencing the specific data node. That was solved by saving the key as well when I upload the data.
I'm using firebase realtime db, and I'm storing a list of string in a particular storage reference. Currently, to add something to the list
I'm doing the following steps.
Read the database childreference
get the datasnapshot and check if it is null (which means first
time)
if it is null, directly set your local list
if dataSnapshot.getValue(); not null then (already data present in
the db, so need to append the new data to th e end of it.)
save the remote list from dataSnapshot.getValue(); to a local variable.
then add the new data to the end of it
now the local list contains all the items in remote as well as new
items. save this to the child reference
Below is the code I have written for that
DatabaseReference reference = root()
.child(userId)
.child(list_id);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
reference.removeEventListener(this);
List<String> value = new ArrayList<>();
if (dataSnapshot.getValue() == null) {
value.add(message);
} else {
if (dataSnapshot.getValue() instanceof List && ((List) dataSnapshot.getValue()).size() > 0 && ((List) dataSnapshot.getValue()).get(0) instanceof String) {
value = (List<String>) dataSnapshot.getValue();
value.add(message);
}
}
reference.setValue(value, (databaseError, databaseReference) -> {
finish();
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
finish();
}
private void finish() {
Log.e(TAG,"save finished");
}
});
Thats a lot of steps to do a simple operation. Also , all the time I'm pulling the whole data from remote and appending the new data to it.
is there any easy way to do this? I tried with the 'push()' method as follows
DatabaseReference reference = root()
.child(userId)
.child(list_id).push();
But it adds a new key always to the value I add. Can anyone explain what is the proper way to do it with less code?
UPDATE:
My db structure is as shown below
The solution you gave it's very good but why to remove the listener inside the callback?
I'll write you the code to be more simpler. Please see it below:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference listIdRef = rootRef.child("list").child(list_id);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String comment = ds.getValue(String.class);
list.add(comment);
}
//Do what you need to do with your list
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage());
}
};
listIdRef.addListenerForSingleValueEvent(valueEventListener);
Don't ignore errors.
The simplest way in which you can add a new child in your 08-10-18 node, without the need to get the enitire list, would be using only the following lines of code:
Map<String, Object> map = new HashMap<>();
map.put("5", "comment55");
rootRef.child("list").child(list_id).updateChildren(map);
But even a better solution would be to use instead of lists, maps and the children should be added using the push() method. So your database structure should look like this:
Fireabase-root
|
--- usr100
|
--- 08-10-18
|
--- randomId: "comment1"
|
--- randomId: "comment2"
|
--- randomId: "comment3"
|
--- randomId: "comment4"
And the code should look like this:
String key = rootRef.child("list").child(list_id).push().getKey();
Map<String, Object> map = new HashMap<>();
map.put(key, "comment5");
rootRef.child("list").child(list_id).updateChildren(map);
In this case you don't have to worry about the key, which is not a number anymore. Without the help of the push() method, you need to get the entire list, as explained in the first part of my answer, add the new element and the update the list in the database.
This is just an update to the existing accepted answer, which I tried and working. This is the same process with less lines of code, without using the ValueEventListener and making use of the updateChildren method as mentioned in the accepted answer.
DatabaseReference reference = deviceRootReference().child(userId).child(list_id).push();
Map<String, Object> map = new HashMap<>();
map.put(reference.getKey(), comment);
Tasks.await(reference.updateChildren(map));
NOTE: This code performs the db write synchronously (Tasks.await blocks the thread), so the above piece of code should run in a background thread only
Hello guys I am new to Firebase and I am trying to retrieve all data under Uid.
I store them like this:
mDatabase=FirebaseDatabase.getInstance().getReference().child("Data").child(auth.getCurrentUser().getUid());
//some other code here
DatabaseReference newProduct =mDatabase.child(category).child("Product").push();
newProduct.child("productname").setValue(name);
newProduct.child("date").setValue(date);
My question is how can I retrieve all data under userUid category? Do I need something like .child(*).child("Products")?
What you need to do is use a listener to retrieve that data, something along the lines of
mDatabase.child(category).child("Product").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child("productname").getValue;
String date = (String) dataSnapshot.child("date").getValue;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
There you go, now you pulled all that data as Strings.
Also, I would suggest that instead of
auth.getCurrentUser().getUid()
use
String uid = (String) auth.getCurrentUser().getUid();
and just put uid in there instead, that way your code is much cleaner and everytime you need to refer to uid, you have a string for it.