I am using Firebase-UI in my android project with email/password provider. The structure of the database is:
profiles
user-id
age
height
user-id
On signup I want to enter a new node in profiles with default values. The user can edit and save the values later. For an existing user I just want to read the values and display them in the UI. I have tried using ChildEventListener and dataSnapshot.hasChild(uid) to detect if the user already exists but it isn't working. This is the AuthStateListener:
mAuthStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = mFirebaseAuth.getCurrentUser();
if(user != null)
{
onSignedInInitialize(user);
}
else
{
onSignedOutCleanup();
startActivityForResult(AuthUI.getInstance().createSignInIntentBuilder().setProviders(providers).build(), SIGN_IN);
}
}
};
This is what I have tried:
private void onSignedInInitialize(final FirebaseUser user) {
userRef = mProfilesDBReference.child(user.getUid());
if(mValueEventListener == null)
{
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue() == null)
{
UserProfile profile = new UserProfile("username", null, 100, 100);
userRef.setValue(profile);
UpdateUI(profile);
}
else
{
UserProfile profile = dataSnapshot.getValue(UserProfile.class);
UpdateUI(profile);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
}
userRef.addValueEventListener(mValueEventListener);
}
Lets say the userid is stored in uid;
You can fetch the height and age like this.
DatabasReference userRef = database.getReference("profiles").child(uid);
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue() == null){
//User data doesnt exist
}
else
{
HashMap<String,String> userMap =
(HashMap<String,String>)dataSnapshot.getValue();
String age = userMap.get("age");
String height = userMap.get("height");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Note that i have assumed that you have stored them as Strings , firebase usually converts ints to longs. So if you used ints , convert the value type of hashmap as Long.
A much better way would be to create a POJO class.
Related
I am reading user profile from database, but the first time I read, it returns the right value (full attributes of a user object), but the second time it fires, it returns only 1 attribute (other attributes is null). this is my code
if (mProfileValueEvent != null) mProfileRef.removeEventListener(mProfileValueEvent);
mProfileValueEvent = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (getFirebaseUser() != null) {
if (dataSnapshot.exists()){
final User user = dataSnapshot.getValue(User.class);
Log.d("RRRRRRRR1",dataSnapshot+"");
if (user != null) {
Log.d("RRRRRRRR2",user.getName()+"");
tv_name.setText(user.getName());
tv_email.setText(user.getEmail());
tv_status.setText(user.getStatus());
setAvatarToView(user.getThumbAvatarUrl(), user.getName(), civ_avatar);
setMyGlobalProfile(user);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mProfileRef.addValueEventListener(mProfileValueEvent);
this is the log cat :
/RRRRRRRR1: DataSnapshot { key = kk44p2XW97OIxAudLwekOZwZM7B2, value = {password=12345678, status="pla pla", verified=true, userId=kk44p2XW97OIxAudLwekOZwZM7B2, dateofbirth=18/08/2003, lastSeen=1575100843974, email="email#gmail.com", name=Mẫn Mẫn, gender=Nữ, joinedDate=18/08/2019} }
/RRRRRRRR2: Mẫn Mẫn
/RRRRRRRR1: DataSnapshot { key = kk44p2XW97OIxAudLwekOZwZM7B2, value = {lastSeen=-1} }
2019-11-30 15:05:22.377 24224-24224/com.example.tranquoctrungcntt.uchat D/RRRRRRRR2: null
version of library
implementation 'com.google.firebase:firebase-database:19.2.0'
THIS IS THE COMPLETE CODE I USE TO READ THE USER PROFILE
Check connection to know user online or offline
mDatabaseConnectionValueEvent = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
boolean isConnected = dataSnapshot.getValue(Boolean.class);
if (isConnected) {
final DatabaseReference ACTIVE_REF =
ROOT_REF.child(CHILD_USERS).child(getMyUID());
Map<String, Object> mapOnline = new HashMap<>();
mapOnline.put(kLastSeen, -1);
ACTIVE_REF.updateChildren(mapOnline);
} else {
final DatabaseReference ACTIVE_REF =
ROOT_REF.child(CHILD_USERS).child(getMyUID());
Map<String, Object> mapOffline = new HashMap<>();
mapOffline.put(kLastSeen, getCurrentTimeInMilies());
ACTIVE_REF.updateChildren(mapOffline);
}
updateDatabaseConnectionStatus(isConnected);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
CONNECT_REF.addValueEventListener(mDatabaseConnectionValueEvent);
*Then, I read user profile like this : *
mProfileValueEvent = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (getFirebaseUser() != null) {
final User user = dataSnapshot.getValue(User.class);
//should set up UI, but the snapshot contains only one key
// "lastSeen"
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mProfileRef.addValueEventListener(mProfileValueEvent);
NOTE: This issue only happens when app first launch. After the first launch, it works fine (return enough data, I think because the data is cached)
The Firebase client always fires with the complete snapshot of the data at a location. So if you get this output:
DataSnapshot { key = kk44p2XW97OIxAudLwekOZwZM7B2, value = {lastSeen=-1} }
There is some code that writes to kk44p2XW97OIxAudLwekOZwZM7B2 with just a lastSeen value. You might want to check your code for calls to setValue(), as that would explain why the previous data under kk44p2XW97OIxAudLwekOZwZM7B2 disappeared in that second snapshot.
I want to read 2 values from Firebase (if exist as in first user there are not) and if needed to update them. Actually i m trying at first to do it with one value, with no luck. My code is
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
final String uid = Objects.requireNonNull( mAuth.getCurrentUser() ).getUid();
mScoreReference.child( uid ).addListenerForSingleValueEvent( new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User oldscore = dataSnapshot.getValue( User.class );
if (dataSnapshot.exists()) {
if(oldscore.getScore()==null){
oldscore.setScore(String.valueOf( 0));
String oldscorevalue = Objects.requireNonNull(oldscore).getScore();
int convertedscore = Integer.parseInt(oldscorevalue);
if (convertedscore > 0) {
//Upload points to Database
mScoreReference.child(uid).child( "Score" )
.setValue( convertedscore + newScore );
} else mScoreReference.child(uid).child( "Score" ).setValue( newScore );
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
} );
I managed to convert null(the first value as score is not exist) and to set score. So my problem is why i cant update the value, and how can i update 2 values at the same time? Probably i have to use Transaction, but i m not familiar at all with this. I m reading, but i cant find how to convert this code to Transaction.
UPDATE
I tried with Transaction.
mScoreReference.child( uid ).runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
User user = mutableData.getValue(User.class);
if (user.getScore() == null) {
mScoreReference.child(uid).child( "Score" ).setValue( newScore );
}
else{
String oldscorevalue = Objects.requireNonNull(user).getScore();
int convertedscore = Integer.parseInt(oldscorevalue);
mScoreReference.child(uid).child( "Score" )
.setValue( convertedscore + newScore );
}
// Set value and report transaction success
mutableData.setValue(user);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "postTransaction:onComplete:" + databaseError);
}
});
and i have strange results. At first time do nothing, then adds Score and another irelavent User value, and after this adds 2 Score fields in Database.
For some reason when receiving data from fire base real time database, no matter which account I log into or whatever the database will always return "points" as 0, even when the value store in the database is not zero. The Uid is definitely correct as I checked that.I do not understand why and I have been trying to fix this problem for a while now.The code has worked in different activities and nothing has changed.
databaseUsers =FirebaseDatabase.getInstance().getReference("Users");
final FirebaseAuth firebaseAuth;
firebaseAuth = FirebaseAuth.getInstance();
user = firebaseAuth.getCurrentUser();
databaseUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
points = dataSnapshot.child(user.getUid()).child("points").getValue(int.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//Getting Total Points from Firebase Database
databaseUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
totalpoints = dataSnapshot.child(user.getUid()).child("totalpoints").getValue(int.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
To solve this, please use the following code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("Users").child(uid);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long points = dataSnapshot.child("points").getValue(Long.class);
Log.d("TAG", points + "");
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
uidRef.addListenerForSingleValueEvent(valueEventListener);
Don't also forget to set your security rules like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
So only authenticated users can read or write data to your database.
The Solution that I found was to move the section of the code that displayed "points" in a text view to inside the "onDataChange" subroutine.
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("Users").child(uid);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Integer value = dataSnapshot.child("points").getValue(Integer.class);
if (value != null) {
points = value;
} else {
points = 0;
}
value = dataSnapshot.child("totalpoints").getValue(Integer.class);
if (value != null) {
totalpoints = value;
} else {
totalpoints = 0;
}
txtpoints.setText("Points: "+ points);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("my tag","data Snapshot Cancelled");
}
};
uidRef.addListenerForSingleValueEvent(valueEventListener);
I have a ValueEventListener, and the inner code is never being reached. My app is authenticating, but I can't retrieve data and I'm not sure what I'm missing. In the code below, when I check, uid has the correct value, and the data path ("Users/[uid]") is correct, but none of the inner code in the value event listener is never being reached. I've also tried to place a listener right at the root, with the same result.
I've set up Firebase using the menu options, adding both Authentication and Realtime Database to my app; authentication is working fine, so I'm wondering if there is something else that needs to be configured for the realtime database? I've read the documentation and walked through many examples but I can't see anything I'm missing.
uid = FirebaseAuth.getInstance().getCurrentUser().getUid().toString();
DatabaseReference userRef = ref.child("Users").child(uid).getRef();
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user == null) {
SettingsLoad();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("User", "User not found" );
}
};
userRef.addListenerForSingleValueEvent(userListener);
Try this!
I've just added else condition and log or toast the results!!
uid = FirebaseAuth.getInstance().getCurrentUser().getUid().toString();
DatabaseReference userRef = ref.child("Users").child(uid).getRef();
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user == null) {
SettingsLoad();
}
**else {
Log.d("tag","User Found!");
}**
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("User", "User not found" );
}
};
userRef.addListenerForSingleValueEvent(userListener);
{
users:
{
apple:
{
username : apple
email : apple#xy.com
uid : tyutyutyu
}
mango:
{
username : mango
email : mango#xy.com
uid : erererer
}
}
}
This is what I am doing
CREATING USER if checkUsername method returns 0
if(checkFirebaseForUsername(username)==0) {
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(SignUpActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getBaseContext(),"inside",Toast.LENGTH_LONG).show();
User newUser = new User();
newUser.setUserId(mAuth.getCurrentUser().getUid());
newUser.setUsername(username);
newUser.setEmailId(email);
try{
mRef.child("users").child(username).setValue(newUser);
}
catch(Exception e){
Toast.makeText(SignUpActivity.this,"error while inserting",Toast.LENGTH_LONG).show();
}
AlertDialog.Builder builder = new AlertDialog.Builder(SignUpActivity.this);
builder.setTitle(R.string.signup_success)
.setPositiveButton(R.string.login_button_label, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(SignUpActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(SignUpActivity.this);
builder.setTitle(R.string.signup_error_title)
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
My checkUsername method -
public int checkFirebaseForUsername(String passedUsername){
final int[] flag = {0};
final String myPassedUsername = passedUsername;
Log.e("tag","working now");
//flag[0]=1;
DatabaseReference mTest = FirebaseDatabase.getInstance().getReference();
mTest.child("users").child(passedUsername).addChildEventListener(new ChildEventListener() {
#Override
public void onDataChanged(DataSnapshot dataSnapshot) {
Log.e("tag","checking");
if(dataSnapshot.exists()){
Log.e("tag","exists");
flag[0]=1;
}
}
#Override
public void onCancelled(DataSnapshot datasnapshot){
}
});
if(flag[0]==1)
return 1;
else
return 0;
}
This is how I am inserting users in my firebase-database and I want to check if a username is available for a new user or not.
Therefore I need to check is there any user already registered with that username....Please help I have already tried whatever I could understand after reffering to documentation provided on the official firebase blog but all in vain!!
EDIT: New answer, old one still below.
I would get rid of your method "checkFirebaseForUsername" because it will always return 0, no matter what.
What you need to do is this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("users").child("username").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
// use "username" already exists
// Let the user know he needs to pick another username.
} else {
// User does not exist. NOW call createUserWithEmailAndPassword
mAuth.createUserWithPassword(...);
// Your previous code here.
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Old Answer:
{
users:
{
apple[X]:
{
username : apple[Y]
email : apple#xy.com
uid : tyutyutyu
}
mango:
{
username : mango
email : mango#xy.com
uid : erererer
}
}
}
If for example, the node apple[X] will always have the same name as the child property "username":apple[Y], then it is as simple as this.
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("users").child("username").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
// use "username" already exists
} else {
// "username" does not exist yet.
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
however, if say, the node apple[X] can have a different value than the property apple[Y], and you want to see if any node exists where the "username" property is the same, then you will need to do a query.
Query query = FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo("usernameToCheckIfExists");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getChildrenCount() > 0) {
// 1 or more users exist which have the username property "usernameToCheckIfExists"
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
You may try this.
final String userName = unameEditText.getText().toString();
databaseReference.child("users").orderByChild("username").equalTo(userName).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i(Constants.TAG, "dataSnapshot value = " + dataSnapshot.getValue());
if (dataSnapshot.exists()) {
// User Exists
// Do your stuff here if user already exists
Toast.makeText(getApplicationContext(), "Username already exists. Please try other username.", Toast.LENGTH_SHORT).show();
} else {
// User Not Yet Exists
// Do your stuff here if user not yet exists
}
}
#Override
public void onCancelled (DatabaseError databaseError){
}
}
);
You just check if user is already exits or not by below code:
private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
final String userName = "your_user_name"; // replace with your user name
mDatabase.child("users").child(userName).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// User Exists
// Do your stuff here if user already exits
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "getUser:onCancelled", databaseError.toException());
}
});
You can also see Firebase doc for the same on below link:
Read data once