My main goal is to delete an account on both Firebase Auth and Firebase Database. I'm using an interface to synchronize the reception of data, a button to delete and a function to return my User.
Initial variables:
FirebaseAuth mAuth = FirebaseAuth.getInstance();
final FirebaseUser mUser = mAuth.getCurrentUser();
DatabaseReference mUserRef = FirebaseDatabase.getInstance().getReference("Users");
The interface:
public interface IMyInterface {
void returnUser(User user);
}
The button to delete User:
btnDeleteAccount.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
readUser(new IMyInterface() {
#Override
public void returnUser(User user) {
String email = user.getEmail();
String password = user.getPassword();
Log.d("EMAIL+PASSWORD", email+password);
AuthCredential credential = EmailAuthProvider
.getCredential(user.getEmail(), user.getPassword());
mUser.reauthenticate(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()) {
mUser.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
mUserRef.child(mUser.getUid()).removeValue();
mAuth.signOut();
finish();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
Toast.makeText(MainActivity.this, "User account deleted!", Toast.LENGTH_SHORT).show();
}
}
});
}
}
});
}
});
}
});
And the function to retrieve a User with user informations:
private void readUser(final IMyInterface myCallback) {
mUserRef.child(mUser.getUid()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
user = dataSnapshot.getValue(User.class);
myCallback.returnUser(user);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
So, after calling the button, it calls the function to receive the user informations (email and password) and then it uses both information to delete and log out. The problem is that when the last command inside the button ends, it restarts the button at String email = user.getEmail(), but since it does not have an User instantiated, the getEmail() method returns null and the app crashes.
Why is it returning again the method? Or is there something about synchronization which I'm missing? I do have another button which ends when User info is used and it needs to change activity.
You have this behaviour because you are using addValueEventListener method instead of addListenerForSingleValueEvent. Mosty, both do the same thing but there is a difference, addListenerForSingleValueEvent disconnects straight after getting the data, while addValueEventListener keeps listening.
So to sovle this, use the addListenerForSingleValueEvent method or remove the listener according to the life-cycle of your activity.
Related
This code is working fine till public void onSuccess(Void aVoid) but right after its execution, the activity redirects to the previous activity instead of staying on it, and then the toast message appears.
I want it to stay on the activity after registering the user.
mFireBaseAuth = FirebaseAuth.getInstance();
mfirebaseDatabase = FirebaseDatabase.getInstance();
mFireBaseAuth.createUserWithEmailAndPassword(e_mail, password).addOnCompleteListener(StudentSignUp.this, new OnCompleteListener<AuthResult>()
{
#Override
public void onComplete(#NonNull Task<AuthResult> task)
{
if(!task.isSuccessful())
{
Toast.makeText(StudentSignUp.this, "Please check your network or try again using different E-mail.", Toast.LENGTH_SHORT).show();
//loadingBar.dismiss();
}
else
{
StudentDetails studentCredentials = new StudentDetails( studentId, name, e_mail, password );
String uId = task.getResult().getUser().getUid();
mfirebaseDatabase.getReference().child("Student").child(uId).setValue(studentCredentials).addOnSuccessListener(new OnSuccessListener<Void>()
{
#Override
public void onSuccess(Void aVoid)
{
Toast.makeText(StudentSignUp.this, "Your Student is Registered & account has been created.", Toast.LENGTH_SHORT).show();
//loadingBar.dismiss();
}
});
}
}
});
}
Why you need to pass the context in the onCompleteListener.
The code should be like:
mFireBaseAuth.createUserWithEmailAndPassword(e_mail, password).addOnCompleteListener(new OnCompleteListener<AuthResult>()
{
#Override
public void onComplete(#NonNull Task<AuthResult> task)
{
if(!task.isSuccessful())
{
Toast.makeText(StudentSignUp.this, "Please check your network or try again using different E-mail.", Toast.LENGTH_SHORT).show();
//loadingBar.dismiss();
}
else
{
StudentDetails studentCredentials = new StudentDetails( studentId, name, e_mail, password );
String uId = task.getResult().getUser().getUid();
mfirebaseDatabase.getReference().child("Student").child(uId).setValue(studentCredentials).addOnSuccessListener(new OnSuccessListener<Void>()
{
#Override
public void onSuccess(Void aVoid)
{
Toast.makeText(StudentSignUp.this, "Your Student is Registered & account has been created.", Toast.LENGTH_SHORT).show();
//loadingBar.dismiss();
}
});
}
}
});
And instead of using onCompleteListener and then if(!task.isSuccessful()), you can also use onSuccessListener, and sometimes we forget to check if(!task.isSuccessful()) so better use onSuccessListener😀
Feel free to ask if something is unclear. Kindly mark this as the correct answer if it helps you and also in future this answer can help other needy.
I am new to Firebase and I am facing a problem in delete an item from the recycler view I created. but I am unable to understand how to delete items using an auto-generated key. This is how I added item into the database:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("categories");
String key = reference.push().getKey();
reference.child(key).setValue(categoryData).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Toast.makeText(add_category.this, "Category added", Toast.LENGTH_SHORT).show();
finish();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(add_category.this, "Failed to add", Toast.LENGTH_SHORT).show();
}
});
As in your comment, if you want to delete, for example, the second item, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference secondChildRef = rootRef.child("categories").child("-M1qUEGi0u4rX5Ju59r4");
secondChildRef.removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d("TAG", "Second item deleted!");
}
}
});
So to delete a particular item, you to know its ID so you can add it to the reference.
This question already has answers here:
How to redirect multiple types of users to their respective Activities?
(3 answers)
Closed 3 years ago.
I have created a project which has two types of user (patient and doctor). During login, I need to retrieve the role attribute in the firebase which under the users table.
In my database structure, user type maybe is "doctor" or "patient". During login, I think I need to retrieve the role information and then assign them to different activity in android studio. However, my code seems doesn't work. The application keeps stopped. Is there anyone can help me. Thanks in advance.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
email = findViewById(R.id.email);
psd = findViewById(R.id.psd);
}
public void clicked(View v) {
switch (v.getId()) {
case R.id.login:
LoginUser();
break;
case R.id.register:
Intent intent = new Intent(this, ChooseRole.class);
startActivity(intent);
break;
}
}
public void LoginUser() {
String email1 = email.getText().toString().trim();
String psd1 = psd.getText().toString().trim();
mAuth.signInWithEmailAndPassword(email1, psd1)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
indentify();
finish();
} else {
Toast.makeText(Login.this, "couldn't login",
Toast.LENGTH_SHORT).show();
}
}
});
}
public void indentify() {
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseDatabase.getInstance().getReference(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long points = dataSnapshot.child("role").getValue(Long.class);
String role = String.valueOf(points);
if(role=="patient"){
Intent intent = new Intent(Login.this, HomePage.class);
startActivity(intent);
}
else{
Intent intent = new Intent(Login.this, HomePage2.class);
startActivity(intent);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
Hi guys, I changed it like this and it is successful. Thanks for everyone helping :D
public void LoginUser(){
String email1 = email.getText().toString().trim();
String psd1 = psd.getText().toString().trim();
mAuth.signInWithEmailAndPassword(email1, psd1)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()){
currentUser = mAuth.getCurrentUser();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseDatabase.getInstance().getReference("users").child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.child("role").getValue(String.class).equals("patient")) {
startActivity(new Intent(Login.this, HomePage.class));
return;
}
if (dataSnapshot.child("role").getValue(String.class).equals("doctor")) {
startActivity(new Intent(Login.this, HomePage2.class));
return;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}else {
Toast.makeText(Login.this, "couldn't login",
Toast.LENGTH_SHORT).show();
}
}
});
}
Since in your database you have a node called users, then add a reference to that node, for example:
FirebaseDatabase.getInstance().getReference("users").child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Then do the following:
Change this:
if(role=="patient"){
into this:
if(role.equals("patient")){
You need to use equals() when you want to compare the value of each object.
Please help i want to retrieve a specific data from the Firebase Realtime database I have 2 users Professor and Student and i want to use that data for validations.
FireBase Realtime Database
firebaseAuth.signInWithEmailAndPassword(email,pass).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progressDialog.dismiss();
if(task.isSuccessful()){
//The task is successful || Task Login
Toast.makeText(getApplicationContext(),"Successfully Login",Toast.LENGTH_LONG).show();
// If the users is professor but if it is student go to userStudent.class
finish();
startActivity(new Intent(getApplicationContext(),userProf.class));
FireBase Realtime Database
This is what you are looking for
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference reference;
firebaseAuth.signInWithEmailAndPassword(email,pass).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progressDialog.dismiss();
if(task.isSuccessful()){
//The task is successful || Task Login
Toast.makeText(getApplicationContext(),"Successfully Login",Toast.LENGTH_LONG).show();
reference = FirebaseDatabase.getInstance().
getReference("dbname").child(user.getUid());
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){
String usertype=datas.child("user").getValue().toString();
// If the users is professor but if it is
// student go to userStudent.class
if(usertype.equals("Student")){
startActivity(new
Intent(getApplicationContext(),studentProfile.class));
finish();
}else if (usertype.equals("Professor")) {
startActivity(new
Intent(getApplicationContext(),professorProfile.class));
finish();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Try this code
firebaseAuth.signInWithEmailAndPassword(email,pass).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progressDialog.dismiss();
if(task.isSuccessful()){
//The task is successful || Task Login
Toast.makeText(getApplicationContext(),"Successfully Login",Toast.LENGTH_LONG).show();
//user UID
String userId = task.getResult().getUser().getUid();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child(userId);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String user = dataSnapshot.child("user").getValue(String.class);
if (user.equals("Student")) {
startActivity(new Intent(getApplicationContext(),userStudent.class));
} else if(user.equals("Professor")) {
startActivity(new Intent(getApplicationContext(),userProf.class));
}
finish();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Hope it helps
I've traced my code to the root cause of my crashes and apparently this constructor is unable to update the variables of the class. I am getting null pointer exception when I'm trying to get data from this class. You can safely assume that the record is already in the database and all it has to do is just get the data and place it in the class/object. I simply want to get the name for now because I'm testing if the object is still null or not.
class Saver{
private String name;
// constructor of Saver class
public Saver(final String uid) {
Log.d("Saver.java","Reached here"); // this works
FirebaseDatabase.getInstance().getReference().addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Log.d("Saver.java", "OnDataChange"); // does not work
if(dataSnapshot.hasChild("users/" + uid)){
LoadRecord(dataSnapshot, uid);
}
else{
// set a new record into the database
FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
LoadRecord(dataSnapshot, uid);
}
else{
Log.e("Saver.java","Failed to set record in database");
}
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
}
});
}
// This function loads the data into the object
private void LoadRecord(DataSnapshot dataSnapshot, String uid){
Log.d("LifeSaver.java","Uid:"+uid);
// load the existing record in the database
Saver temp = dataSnapshot.child("users/" + uid).getValue(Saver.class);
setName(temp.getName());
}
}
public void setName(String name) {
this.name = name;
}
private Saver CreateNewRecord(FirebaseUser firebaseUser){
Saver saver = new Saver ();
saver.setName(firebaseUser.getDisplayName());
Log.d("saver","saver name: " + saver.getName());
return continuLifeUser;
}
Obviously the function onDataChange will not run until something changed on the database.
How can I manually trigger this function, if possible?
Should I have a DataSnapshot that has the children of this node? If so, how? (show code please so I can visualize what you are explaning)
Is there a better way of doing this?
Edit 1:
Here's the logcat statements from the constructor that should have called the FirebaseDatabase:
D/Saver.java: Reached here with hA4hZrBieISwMOZaMYe7m6K5tpI3
I/DynamiteModule: Considering local module com.google.android.gms.firebase_database:4 and remote module com.google.android.gms.firebase_database:6
I/DynamiteModule: Selected remote version of com.google.android.gms.firebase_database, version >= 6
I/art: DexFile_isDexOptNeeded failed to open oat file '/data/dalvik-cache/x86_64/data#data#com.google.android.gms#app_chimera#m#00000004#DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk#classes.dex' for file location '/data/data/com.google.android.gms/app_chimera/m/00000004/DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk': Failed to open oat filename for reading: No such file or directory
D/Saver.java: Ended here
D/LoginAct.java: Name: null
For getting all the names from all users under users node, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);
The output will be:
Michael Ong
//other names
If you want to get only the name of a particular user, please use the following code:
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
String uid = firebaseUser.getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("users").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = dataSnapshot.child("name").getValue(String.class);
Log.d("TAG", name);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
uidRef.addListenerForSingleValueEvent(eventListener);
The output will be only a single record:
Michael Ong
I resolved the problem by having a loading screen. I should have remembered that the call was Async and that it needed a receiver to call the function that will place the data before moving on to the next activity.
private interface OnGetDataListener {
void onSuccess(DataSnapshot dataSnapshot);
void onFailure();
}
Here's a small code for the listener that you'll have to implement when you're calling the database to get the data. You can check for other posts similar to this one.
Hi first you should add data to database , then only it will work . Looks like there is no data available in Firebase.Just add a key value pair in firebase database , then it will be triggered.
FirebaseDatabase.getInstance().getReference().child("users/" + uid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Log.d("Saver.java", "OnDataChange"); // does not work
if(dataSnapshot!=null){
LoadRecord(dataSnapshot);
}
else{
// set a new record into the database
FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
LoadRecord(dataSnapshot);
}
else{
Log.e("Saver.java","Failed to set record in database");
}
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
}
});
}
// Load record should be like this...
private void LoadRecord(DataSnapshot dataSnapshot){
Log.d("LifeSaver.java","Uid:"+uid);
// load the existing record in the database
Saver temp = dataSnapshot.getValue(Saver.class);
setName(temp.getName());
}
}