I am developing a quiz application whereby a User takes a quiz and after 10 questions the score is saved to a database in Firebase.
Here is my code at present:
String user_id = mAuth.getCurrentUser().getUid();
DatabaseReference current_user_db =
FirebaseDatabase.getInstance().getReference().child("Score").child(user_id);
final int score = mScore;
**databaseUserName = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id).child("username");
databaseUserName.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String username = dataSnapshot.getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});**
//Ensures everything saves at the same time
Map newPost = new HashMap();
newPost.put("Score", score);
**newPost.put("Username", username);**
current_user_db.setValue(newPost);
The part enclosed in ** ** is where I am having some difficulties.
The user signs up to my app using FirebaseAuth, then using the UID I have stored name and username in a 'Users' realtime database.
I would like the score databse to save the final score with the username not the autogenerated UID. I'm just not sure how to get the username and then save it to the new database.
I have also attached a screenshot of how my current database looks.
I have only been using Firebase and Android Studio a few weeks so any help/links are all appreciated.
You can do something like this
final String userName = "userX";
final int score = 55;
FirebaseDatabase db = FirebaseDatabase.getInstance();
db.getReference("Score").child(userName).child("Score").setValue(score).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: updated " + userName + "'s score (" + score + ")");
}
});
Change your String userName to a member.
String user_id = mAuth.getCurrentUser().getUid();
// you can remove child(user_id) if you want to put username directly under Score
DatabaseReference current_user_db = FirebaseDatabase.getInstance().getReference().child("Score").child(user_id);
final int score = mScore;
DatabaseReference databaseUserName = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id).child("username");
databaseUserName.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
userName = dataSnapshot.getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//Ensures everything saves at the same time
Map newPost = new HashMap();
newPost.put("Score", score);
newPost.put("Username", username); // I don't think you need this.
current_user_db.child(username).setValue(newPost);
Let me know if it works.
There is no way in which you can simply use username outside onDataChange() method because this method has an asynchronous behaviour which means that is called even before you are trying to get the data from the database. A quick fix to you are problem would be to move the follwing lines of code:
Map newPost = new HashMap();
newPost.put("Score", score);
newPost.put("Username", username);
current_user_db.child(username).setValue(newPost);
Inside onDataChange() method and your problem will be solved but if you need to use the value of username outside the onDataChange() method, then you need to create your own callback and for that I recomend you see the last part of my answer from this post.
Related
I am studying Android and Firebase by myself.
I'm have a problem with storing user information and creating login and user registration functions by linking Android and Firebase.
When saving user information in Firebase, is only one key possible? I want to save more keys.
I tried changing main key, but it's failed.
Sorry. I can't speak English. I'm using a translator now.
enter image description here
I saved user information like in the picture, but there was a problem during the production of the ID search function.
private FirebaseDatabase database = FirebaseDatabase.getInstance(); //파이어베이스 데이터베이스 연동
DatabaseReference databaseReference = database.getReference();
DatabaseReference conditionRef = databaseReference.child("User");
conditionRef.child(userID).child("userID").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String userid = snapshot.getValue().toString();
if(snapshot.exists()){
Toast.makeText(getApplicationContext(), "아이디: " + userid, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "등록되지 않은 회원입니다.", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
The code is as above.
However, because "conditionRef.child(userID)" does not have a userID value, the information cannot be retrieved from Firebase.
The code shown below is the code used to retrieve the multiple users location from Realtime Firebase and assign to the markers on map:
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference userLocationRef = db.child("User_Location");
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
userLocationRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
try {
for (DataSnapshot ds : task.getResult().getChildren()) {
String userID = String.valueOf(ds.child("userID").getValue());
String encryptedLatitude = ds.child("You").child("l").child("0").getValue(String.class);
String encryptedLongitude = ds.child("You").child("l").child("1").getValue(String.class);
Log.d("encryptedLocation", encryptedLatitude + ", " + encryptedLongitude); //Check the values
Log.d("userid", userID); //Check the values
//decrypt
LocationEncryption locationEncryption = new LocationEncryption();
String decryptedLatitude = null;
String decryptedLongitude = null;
decryptedLatitude = locationEncryption.decrypt(encryptedLatitude);
decryptedLongitude = locationEncryption.decrypt(encryptedLongitude);
Log.d("Decrypted", decryptedLatitude + ", " + decryptedLongitude); //Check the values
double lat = Double.valueOf(decryptedLatitude);
double lng = Double.valueOf(decryptedLongitude);
//Add location on Google Map
LatLng location = new LatLng(lat, lng);
if (hm.containsKey(userID)) {
hm.get(userID).remove();
}
currentLocationMarker = mMap.addMarker(new MarkerOptions().position(location).title(userID));
currentLocationMarker.showInfoWindow();
hm.put(userID, currentLocationMarker);
}
}
catch (Exception e){
e.printStackTrace();
}
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
The structure of the real-time firebase is as follow:
The result of the code is as follow:
When I click on the marker, it only shows the userID of the user. I want the marker to show the name of the user together with the userID. But the problem is that the multiple users' names are stored in Firestore.
The structure of the Firestore is as follow:
The admin details and the user details are stored in the same collection "Users". The fields "isAdmin" and "isUser" are the method to differentiate them. I only need the username and the admin name is not required.
So, how to retrieve multiple users' names from Firestore and assign the names to the correct markers on the map.
When I click on the marker, it only shows the userID of the user. I want the marker to show the name of the user together with the userID.
The best option that you have is to store the name of the user right near the userID. There is no need to create another database call to only get the name of the user. So your new database schema should look like this:
Firebase-root
|
--- User_Location
|
--- $uid
|
--- userID: "Jk8i...1jy2"
|
--- userName: "Zi Zian Yeo" 👈
And in code should look like this:
String userID = ds.child("userID").getValue(String.class);
String userName = ds.child("userName").getValue(String.class);
And to add these values as a title of the marker please use the following lines of code:
String title = userID + "/" + userName;
currentLocationMarker = mMap.addMarker(new MarkerOptions().position(location).title(title));
i have a probleme and i don't know how to solve this.
userRef.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot priereSnapshot : dataSnapshot.getChildren()){
//takeFromDataBase
LocationUser locationUser = priereSnapshot.getValue(LocationUser.class);
double longitudeD = Double.valueOf(locationUser.locationUserLongitude);
double latitudeD = Double.valueOf(locationUser.locationUserLatitude);
//createMarkerFromDataBase
LatLng Test = new LatLng(latitudeD, longitudeD);
String idNum = userRef.getKey();
MarkerOptions optionsTest = new MarkerOptions().position(Test).title("Janaza le: " + locationUser.locationUserDate);
map.addMarker(optionsTest).setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
//createLayoutFromInfoUser
String adresseD = locationUser.locationUserAdresse;
String dateD = locationUser.locationUserDate;
String heureD = locationUser.locationUserTime;
adresse_txt.setText(adresseD);
date_txt.setText(dateD);
heure_txt.setText(heureD);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
It's ok when the marker is getting the date and the hour, but when i want to show other information from the same getkey(), it's not working.
For exemple, when i'm clicking on the marker 3 for (12/07/2020), the app need to put the right information relate to this date on firebase from the same getKey, but it's not working.
the thing is that i don't know how to link all data from the same getkey()
Can you help me please?
I'm not sure I understand correctly, but I think your problem may be here:
String idNum = userRef.getKey();
This gets the key of the userRef, which is the location that you listen to.
More likely you want to get the key of the specific user snapshot, for the current iteration of the loop. To do that, you'll want to get the key of the snapshot:
String idNum = priereSnapshot.getKey();
From this I want take the value of email from mailID and subject, title from mailText.i'm able to access the value of single child but when it show null with when try get with all three.
Following code working for single child:
DatabaseReference databaseRef = database.getReference("/");
databaseRef.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
ArrayList<String> email = new ArrayList();
for (DataSnapshot sd: dataSnapshot.getChildren()) {
String emailStr = sd.child("email").getValue(String.class);
email.add(emailStr);
System.out.println(email);
}
latch.countDown();
}
Above code gives me array contain the all email like that i want to take value of email,title and subject.
Assuming that the new node is a direct child of your Firebase root, to achieve what you have explained in your comments, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference newRef = rootRef.child("new");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.child("mailID").getChildren()) {
String email = ds.child("email").getValue(String.class);
String name = ds.child("name").getValue(String.class);
Log.d("TAG", email + " / " + name);
}
for(DataSnapshot ds : dataSnapshot.child("mailText").getChildren()) {
String title = ds.child("title").getValue(String.class);
String subject = ds.child("subject").getValue(String.class);
Log.d("TAG", title + " / " + subject);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
newRef.addListenerForSingleValueEvent(valueEventListener);
As you see, you need to attach a listener one step higher in your tree hierarchy and to loop throught the children using getChildren() method twice.
You need to change the database structure(there is no join in firebase), to be able to query and get the required data:
new
mailId
email: userx#gmail.com
name:userx
title: test title
Body: test body
Then you will be able to retrieve the required data for the user.
You can also use Queries to be able to get the related data, example:
DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("new");
ref.orderByChild("email").equalTo("userx#gmail.com");
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
This is my fire base data structure:
I am retrieving the data from database using the following method
private DatabaseReference mFirebaseDatabase=FirebaseDatabase.getInstance().getReference();;
private FirebaseDatabase mFirebaseInstance;
mFirebaseDatabase.child("users").child(userId).child(time).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
Log.d("Tag", "Value is: " + value);
System.out.println("Values is :::::::::::::::::::::::::::::::::::: "+value);
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Failed to read value
Log.w("Tag", "Failed to read value.", databaseError.toException());
}
});
i am getting the below error
Caused by: java.lang.NullPointerException: Can't pass null for argument 'pathString' in child()
please help
userID part, this is where i create a new entry to store data to the table
private void createUser(String name, String time, String lat, String lon) {
// In real apps this userId should be fetched
// by implementing firebase auth
if (TextUtils.isEmpty(userId)) {
userId = mFirebaseDatabase.push().getKey();
System.out.println("Userid is ------------------------------> "+userId);
}
User user = new User(name, time,lat,lon);
mFirebaseDatabase.child(userId).setValue(user);
addUserChangeListener();
}
/**
* User data change listener
*/
private void addUserChangeListener() {
// User data change listener
mFirebaseDatabase.child(userId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
// Check for null
if (user == null) {
Log.e(TAG, "User data is null!");
return;
}
Log.e(TAG, "User data is changed!" + user.name + ", " + user.time);
System.out.println("User data is changed!" + user.name + ", " + user.time);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e(TAG, "Failed to read user", error.toException());
}
});
}
The above code is used for userId generation,userId is dynamically created every time when a insert function is called
make sure you're placing a value into either userId or child and that they're at least instantiated (should at least get rid of the nullpointerException)
There is something wrong with the path you are assigning the ValueEventListener to.
Looking from your Firebase Database picture the only problem that could cause that NullPointerException is when you use .child(userId) or when you use .child(time)
How to fix your problem:
replace this .child(time) to .child("time")
make sure you are retrieving the userId this way:
private FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
...
protected void onCreate(Bundle savedInstanceState) {
...
String userId = user.getUid();
...
}