I'm using Firebase for login, but I want the user to also be added to the Real-Time Database so I can link the User with further data.
When a user registers, I can see that the user has been added to the authentication section of Firebase, and the user is able to log in but it does not get added to the Real-Time Database.
Here is my code
db = FirebaseDatabase.getInstance();
users = db.getReference("Users");
User user = new User();
user.setEmail((editEmail.getText().toString()));
user.setPassword((editPass.getText().toString()));
user.setName((editName.getText().toString()));
user.setPhone(editPhone.getText().toString());
users.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.setValue(user)
I also set an onSuccess/fail listener with Toasts letting me know if it failed or not. And neither of the toasts execute. I do have read/write enabled on my DB.
Define Variable.
private DatabaseReference userRef;
in OnCreate method.
userRef = FirebaseDatabase.getInstance().getReference().child("Users");
in a signup button
String getUserName = usernameEditText.getText.toString;
String getBio = bioEditText.getText.toString;
//and you should use the validates
if(getUserName.equals("")
{
usernameEditText.setError("Field Required");
}
else if(getBio.equals("")
{
bioEditText.setError("Field Required");
}
else
{
final HashMap<String , Object> profileMap = new HashMap<>();
profileMap.put("uid" , FirebaseAuth.getInstance().getCurrentUser().getUid());
profileMap.put("name" , getUserName);
profileMap.put("status" , getBio);
userRef.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.updateChildren(profileMap)
.addOnCompleteListener(new OnCompleteListener<Void>()
{
#Override
public void onComplete(#NonNull Task<Void> task)
{
if (task.isSuccessful())
{
Log.v("Profile Updated" , "Profile Updated Successfully");
Intent intent = new Intent(SettingsActivity.this , MainActivity.class);
startActivity(intent);
finish();
progressDialog.dismiss();
Toast.makeText(SettingsActivity.this, "Your profile Info has been updated", Toast.LENGTH_SHORT).show();
}
}
});
}
Related
This question already has answers here:
How to redirect multiple types of users to their respective Activities?
(3 answers)
Checking if a particular value exists in the Firebase database
(6 answers)
Closed 2 years ago.
First, I will tell the flow of my App.
Login Screen(SignInActivity.java) -> Enter details(MainActivity.java) ->Home Screen(HomeScreenActivity.java)
In my app, I have used Firebase Authentication and Firebase Database. When the user is new, then it should go to Main Activity from SignInActivity where user enters his name, a short description and his hobby. The details are stored in Firebase Database and then HomeScreenActivity opens where user details are shown in Recycler View.
But currently what happens is when same user does login again, it again asks user for details. I want to check if users Google Account already exists in Firebase Auth, then instead of asking details, it should directly go to HomeScreenActivity.
I checked many answers on StackOverflow, but nothing seems to work. One thing that i tried was additionalUserInfo.isNewUser but in this app crashes when user does login again, showing null error where I display user details in HomeScreenActivity.
SignInActivity.java
private void firebaseAuthWithGoogle(String idToken) {
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
mAuthIn.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "SignInWithCredential:success");
startActivity(new Intent(SignInActivity.this, MainActivity.class));
finish();
} else {
// If sign in fails, display a message to the user.
Toast.makeText(SignInActivity.this, "Authentication Failed", Toast.LENGTH_SHORT).show();
}
}
});
}
MainActivity.java
public void init() {
hobbiesContinueButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String name=user.getText().toString().trim();
String desc=description.getText().toString().trim();
String hobby=spinner.getSelectedItem().toString();
String image="default";
String thumbnail="default";
if(!TextUtils.isEmpty(name))
{
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
assert currentUser != null;
String userId=currentUser.getUid();
User user=new User(name,hobby,desc,image,thumbnail);
dbRef.child(userId).setValue(user);
startActivity(new Intent(getApplicationContext(), HomeScreenActivity.class));
finish();
}
else
{
Toast.makeText(getApplicationContext(), "Enter a name",Toast.LENGTH_SHORT).show();
}
}
});
}
HomeScreenActivity.java
dbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
imgvw = headerView.findViewById(R.id.imageView);
imgvw.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//to open gallery
Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(galleryIntent, "SELECT IMAGE"), GALLERY_PICK);
}
});
TextView nameDrawer = findViewById(R.id.navName);
TextView descDrawer = findViewById(R.id.navDescription);
User change = snapshot.getValue(User.class);
assert change != null;
//This is where null error occurs
nameDrawer.setText(change.getUserName());
descDrawer.setText(change.getUserDesc());
//change profile picture
image= Objects.requireNonNull(snapshot.child("userImage").getValue()).toString();
Log.d(TAG, "onComplete: "+image);
if(!image.equals("default")){
Picasso.get().load(image).placeholder(R.drawable.avatar).into(imgvw);
}
}
The solution is to save your user details in shared preferences for the first time when the user sign in , then after the user signs out and sign it again , you get data from shared preferences and set them directly to your edittexts
Try this Code :
///save sharedpreferences
SharedPreferences sharedPreferences =
getSharedPreferences("prefs",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("username","put here your username"); //
editor.putString("email","put your email here"); //you can add more details
editor.apply();
///get sharedpreferences
SharedPreferences sharedPreferences1 =
getSharedPreferences("prefs",Context.MODE_PRIVATE);
String username = sharedPreferences1.getString("username","");
String email = sharedPreferences1.getString("email","");
//then here set the valeus from sharedpreferences to your edittexts
I am trying to retrieve profile data of the currently logged in user from Firebase Realtime Database. I have authenticated my users using email and password. I then saved the signup data on the database, as an object as follows: (All of this code is onCreate in SignUpActivity). I saved the data as User objects. My User model class has getters and setters, parameterized and blank constructors.
´´´´// Initialize FirebaseAuth and DatabaseReference
mFirebaseAuth = FirebaseAuth.getInstance();
mDatabaseRef = FirebaseDatabase.getInstance().getReference("users");
mFirebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(SignUpActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
//save all data to database
String mUserId = mFirebaseAuth.getCurrentUser().getUid();
User user = new User(email, name,tel, address1,address2,user_type, mUserId);
//add to database
mDatabaseRef.child(mUserId).setValue(user);
//open main activity
Intent intent = new Intent(SignUpActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
Thus, mUserId is the userId of authenticated users. My database structure is as follows, and the rules are default public.
wish-store-42facaddclose
users
2GbVFSMFrihqVJ8OAXBa56owNW93
address1: "juja"
address2: "Town"
email: "a.bea#gmail.com"
phone: "+237638256239"
userId: "2GbVFSMFrihqVJ8OAXBa56owNW93"
userName: "Beatrice Njambi"
userType: "Buyer Account"
Now, to retrieve data in MainActivity, this is the code I’m using in onCreate:
//instantiate firebaseAuth
mFirebaseAuth = FirebaseAuth.getInstance();
Then onStart;
userName = (TextView) findViewById(R.id.userNameHeader);
//check to see if user is logged in
mFirebaseUser = mFirebaseAuth.getCurrentUser();
if (mFirebaseUser == null) {
//the user is not logged in, start login activity
loadLogInView();
} else {
String mUserId = mFirebaseUser.getUid();
root = FirebaseDatabase.getInstance().getReference();
DatabaseReference mDatabaseRef = root.child("users").child(mUserId);
ValueEventListener profileListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
userName.setText(user.getUserName());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.i("Read failed", databaseError.getMessage());
}
};
mDatabaseRef.addValueEventListener(profileListener);
}
I had tried to debug, and it says there is a null pointer exception for mUserId. So, the problem is correctly referencing the userId of the authenticated users. Please help, I really don’t understand what I’m doing wrong.
Thanks in advance.
Try to add the ValueEventListener for the database object directly, rather than setting it later. Try to check if you have initialized the FirebaseAuth.
mAuth = FirebaseAuth.getInstance();
mAuth.getCurrentUser();
FirebaseUser mUser = mAuth.getCurrentUser();
String uId = mUser.getUid();
String personName=mUser.getDisplayName();
String personEmail=mUser.getEmail();
String personPhoto=mUser.getPhotoUrl();
try this
I'm creating an app with where I want already signed up users to be redirected to their profile if their phone number is registered in the app, but if he is a new user then he will be redirected to the welcome page.
The problem is, I'm able to get the verification code for the phone number, but it is always redirecting to the welcome page irrespective of whether it is an existing user or a new user.
By far I've implemented Firebase phone authentication, and
private void verifyCode(String code) {
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, code);
signInWithCredentials(phoneAuthCredential);
}
private void signInWithCredentials(PhoneAuthCredential phoneAuthCredential) {
mAuth.signInWithCredential(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
final String num = getIntent().getStringExtra("phoneNumber");
final Query query = FirebaseDatabase.getInstance().getReference("users").orderByChild("birthday").equalTo(num);
if (task.isSuccessful()) {
if (num.equals(query.toString())) {
Log.i("Method", "Inside if block");
Log.i("value", num + query.toString());
Intent intent = new Intent(VerifyPhoneActivity.this, WelcomeActivity.class);
startActivity(intent);
} else {
Log.i("Method", "Inside if block2");
Log.i("value", num + query.toString());
Intent intent = new Intent(VerifyPhoneActivity.this, ProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
} else {
Toast.makeText(VerifyPhoneActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
I'm taking only the phone number of the user to log in/sign up, and there's no separate button for login and sign up. It should work in such a way that, once the OTP sent by the Firebase auth has been verified and if the phone number is already present in the database, it should directly fo the user's profile page instead of the welcome screen, however, if the phone number is new it should go to the welcome page instead of the user profile page.
The challenge I'm facing is I'm not able to check if the number entered is already present in the database in the user table(I've created a separate user table to store the details of the user when he signs up for the first time).
from what I understood you're able to register users but you're not able to redirect unregistered users to the login/signup screen, if that's the case then you can try to use
FirebaseAuth.getInstance().currentUser
in the on create view method in your welcome/home page it should be something like this
override fun onCreate(savedInstanceState: Bundle?) {
if (FirebaseAuth.getInstance().currentUser == null) {
startActivity(Intent(applicationContext, RegistrationActivity::class.java))
finish()
return
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// do your other stuff
}
this code is written in kotlin it shouldn't be that different in java. hope it helps.
UPDATE------
you have a few mistakes with your code, try this
private void verifyCode(String code) {
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, code);
FirebaseAuth.getInstance().signInWithCredential(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
final String num = getIntent().getStringExtra("phoneNumber");
FirebaseDatabase.getInstance().getReference("users").orderByChild("phoneNumber").equalTo(num).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Intent intent = new Intent(VerifyPhoneActivity.this, ProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} else {
FirebaseDatabase.getInstance().getReference("users").push().child("phoneNumber").setValue(num).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Intent intent = new Intent(VerifyPhoneActivity.this, WelcomeActivity.class);
startActivity(intent);
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
} else {
Toast.makeText(VerifyPhoneActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
first of all, you have to log in the user with the phone detail then you check if you have any user registered with that phone number if you do then that means that this user has already entered the app but if you didn't have any information of user with that phone number then you create his information and direct him to the welcome screen after creating his information, so if this user comes back again you will check if we have a record of user with that phone number (which we do) so this time he will be directed to the profile screen
I am making a firebase notes app for android as a project (I'm a beginner and never done anything like this). My problem at the moment is that every note made, no matter what user made it, is available for every user to see. I want to make it that every user can only read/write their own notes but all the rules I found and tried so far made it that no notes are sent to the database at all or are not shown. I tried playing around with the code itself as well, but everything I did made the app crash but I'm open to suggestions.
The problem (logged in as user 2) :
The database with two users and the two notes:
I've tried solutions from other similar posts like this:
"rules": {
"tasks": {
"$userId": {
".read": "auth.uid == $userId",
".write": "auth.uid == $userId",
}
}
}
}
But none worked properly so far.
User creation:
fAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
fUserDatabase.child(fAuth.getCurrentUser().getUid()).child("basic").child("name")
.setValue(name).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
progressDialog.dismiss();
Intent mainIntent = new Intent(RegisterActivity.this, MainActivity.class);
startActivity(mainIntent);
finish();
Toast.makeText(RegisterActivity.this, "User Created", Toast.LENGTH_SHORT);
} else {
progressDialog.dismiss();
Toast.makeText(RegisterActivity.this, "Error: " + task.getException().getMessage(), Toast.LENGTH_SHORT);
}
}
});
} else {
progressDialog.dismiss();
Toast.makeText(RegisterActivity.this, "Error: " + task.getException().getMessage(), Toast.LENGTH_SHORT);
}
}
});
Note Creation:
(Not on the same page)
editText = findViewById(R.id.etx);
etd = findViewById(R.id.etdx);
button = findViewById(R.id.btnx);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("posts").push();
Map<String, Object> map = new HashMap<>();
map.put("id", databaseReference.getKey());
map.put("title", editText.getText().toString());
map.put("desc", etd.getText().toString());
databaseReference.setValue(map);
Intent back = new Intent(NewNoteActivity.this, MainActivity.class);
startActivity(back);
}
});
I would like to make it so that every user can only see, edit and delete notes that they made themselves.
I found a solution that might be useful to anyone else who's having troubles with this kind of thing.
I changed the path in the note creation to this:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("posts").push();
Then changed the part of the code that shows the notes accordingly.
This is how it was:
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("posts");
This is how it is now:
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("posts");
You cannot keep data as relational database. because firebase database is flat heierarchy. when you design the database use always
/users/user-id/posts
+ item1
+ item2
this is the way you must implement. thanks.
I'm trying to create users table in Firebase realtime database.However, everytime user re-logins his previously entered data is being removed or overwritten.Couldnt understand how should I change it.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(RegisterActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user=mAuth.getCurrentUser();
final String databaseUserName=user.getDisplayName();
String name=mAuth.getCurrentUser().getDisplayName();
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(RegisterActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(RegisterActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(RegisterActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}
So once I run the code, for the very first time it works perfectly fine and say I edit&add additional user info but once the user logs out and re-enters, everything is cleared out and node is again created.
Here you are saving the data in the database:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
Now on the second time, the data is not getting deleted or cleared, it cannot be deleted magically, the data is getting overridden. All you need to do is add a push() that will create a random id for each log in.
So like this:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users").push();
DatabaseReference userNameRef = myRootRef.child(databaseUserName)
Edit:
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(Activity_name_here.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(getApplicationContext(), "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Authentication failed." + task.getException(),
Toast.LENGTH_SHORT).show();
} else {
Here is the working version of the source code. You can use the very same code for facebook login as well. This code simply prevents user from overwriting when logging in again.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(SignInActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
//getting current users account
FirebaseUser user=mAuth.getCurrentUser();
//getting the display name of the current user to store them in our real time database
final String databaseUserName=user.getDisplayName();
//creating a child called users
final DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
//here we make a control such that, if logged in user is exist in the realtime database
//if not exists, then we save them , if exists we continue with the else statement and break it.
myRootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChild(databaseUserName)){
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//value is also set to user display name however it doenst have to be so
userNameRef.setValue(databaseUserName);
} else{
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(SignInActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(SignInActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(SignInActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}