DocuemntSnapshot on Android is one result late [duplicate] - android

This question already has an answer here:
How to check a certain data already exists in firestore or not
(1 answer)
Closed 2 years ago.
I have an EditText where I type an username. After I click "REGISTER", a function processes the username to check if it already exists:
public boolean usernameExists (String username) {
database.collection("users").document(username).get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete (#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
usernameExists_result = task.getResult().exists();
}
else {
task.getException().printStackTrace();
}
}
});
return usernameExists_result;
}
where database and usernameExists_result are both fields. Of course, since the username is the documentID, this function should return true if the document (and so the username) exists, and false if it doesn't.
Now, the problem is the function - apart from the first call - always returns the value that it should have returned on the previous call.
For example, if on the first call the function returns true because the username already exists, and then I type another username that doesn't exist, the function will also return true. On the next call, it will return false, because that it what it should have returned on the previous call. And on the next call, it will return whatever it should have returned on the previous, and so on.
Does anyone have an explanation for this behavior? I can provide whatever info is needed.

Firebase is not working like this. Try to avoid making a methood boolean INSTEAD just just go on.
Example here:- your button
private void setBtnRegister(){
btnRegister.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
//Check all exception here. (incase editext is null)
//and then put the code here instead that method boolean
database.collection("users").document(username).get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete (#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
//Success, maybe go next step
}
else {
//Fail
}
}
});
}
});
}

Related

I can't toast a String get from Firebase Realtime DB in Android [duplicate]

This question already has answers here:
getContactsFromFirebase() method return an empty list
(1 answer)
Setting Singleton property value in Firebase Listener
(3 answers)
Wait Firebase async retrieve data in Android
(2 answers)
Android + Firebase: synchronous for into an asynchronous function
(1 answer)
Closed 1 year ago.
i'm having a problem with my app. I built a simple login / logout app and it work normally, i want to toast a message every time the user login back but it toasted an empty string ( i log it in logcat and it show up normally ) , i don't know why and how to fix it .
Please help me and tell me if there's better way to get this data from Firebase.
Bellow is the code :
String username = ""; //TO STORE USERNAME - Global variable
private void loginUser(String txt_email, String txt_password) {
auth.signInWithEmailAndPassword(txt_email, txt_password)
.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("firebase_debug", "signInWithEmail:success");
//GET USER NAME
FirebaseUser user = auth.getCurrentUser();
DatabaseReference username_ref = db.getReference("Users");
username_ref.child(user.getUid()).child("username").get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (!task.isSuccessful()) {
Log.e("firebase", "Error getting data", task.getException());
}
else {
Log.d("firebase", String.valueOf(task.getResult().getValue())); // THIS LINE STILL WORK , IT DO LOG THE CORRECT USERNAME
username=String.valueOf(task.getResult().getValue());
}
}
});
Toast.makeText(MainActivity.this,username,Toast.LENGTH_SHORT).show();//TOAST EMPTY STRING ??
startActivity(new Intent(MainActivity.this,ChatRoom_Activity.class));
finish();
} else {
// If sign in fails, display a message to the user.
Log.d("firebase_debug", "signInWithEmail:failure", task.getException());
login_btn.setText("LOGIN");
login_btn.setEnabled(true);
password_input.setText("");
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull #NotNull Exception e) {
Toast.makeText(MainActivity.this,e.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}

FirebaseFirestore add() method being executed before validation (get() documents) [duplicate]

This question already has answers here:
How to return a DocumentSnapShot as a result of a method?
(2 answers)
Closed 2 years ago.
I'm building an APP and using Firestore to create a collections of Users. Before adding the new user to the collection i need to check within the collection if the email is already in use and for this i've built two methods: one for reading the collection looking for an user with that email and the other one to adding the new user IF everything is ok. But no matter what I do, the add method always executes first leading to the validation being useless. I guess it's has something to do with the methods priority withing Firebase but i really couldn't pull out with a solution
Here's the two methods
The first one it's validation and the second one it's the add
private boolean createFirestoreUser(final String identificador) {
final boolean[] isValid = {true};
FirebaseFirestore.getInstance().collection("Usuarios")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
if(identificador.equals(document.getString("identificador")))
isValid[0] = false;
}
}
});
return isValid[0];
}
private void createUser(Usuario novoUsuario) {
FirebaseFirestore.getInstance().collection("Usuarios")
.add(novoUsuario)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(final DocumentReference documentReference) {
documentReference
.update("id", documentReference.getId())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
loginSessionManager.createLoginSession(documentReference.getId());
loginSessionManager.checkLogin(this.getClass());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
snackbar.showMensagemLonga(v,e.getMessage());
}
});
}
The second one is ALWAYS being called first no matter the order i use on the button listener. I've debbuged and it really enters in the isValid[0] = false after the user is added
Where are you calling the methods?
You could just call the createUser inside of the .addOnSuccessListener this way it will not be called until the valdiation is returned.
Something like:
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
if(identificador.equals(document.getString("identificador")))
isValid[0] = false;
else
createUser(novoUsuario)
}
}
The reason why I'm asking where you are calling the methods is because your variable might be by default true which would trigger the second function before the async listener is returned therefore calling the second method before the validation is made.
So the alternative would be to call the register method inside the same mehrod where you are validating or if what I'm assuming that you have a boolean declared first to see if you call the create method, just have it false as default and make sure to be calling it after the async .OnCompleteLister is finished.

Random document that doesnt exist in firestore gets selected on android and deleted

I am trying to delete a document from Firestore. I am trying to do this based on the task ID that was randomly generated by Firestone. when a particular task is selected on android, I want to be able to delete that task. However, when I tried debugging the code, it shows a random ID that doesn't exist on the database and tries to delete that, sending me a success message in the console. I am not sure where I am going wrong. Please advice.
public void deleteTasks(View v) {
userId = mFirebaseAuth.getCurrentUser().getUid();
String tskid= fStore.collection("usersData").document(userId).collection("tasks").document().getId();
DocumentReference taskref = fStore.collection("usersData").document(userId).collection("tasks").document(tskid);
taskref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d("tag", "Task Deleted Successfully");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("tag", "Task Deletion Unsuccessful");
}
});
}
the above delete method is called on the button using android:OnClick
The Task I'd like to delete is Circled
When you are using the following line of code:
String tskid= fStore.collection("usersData").document(userId)
.collection("tasks").document()
.getId();
You are generating a new random ID. Actully, you are reserving a key for a document that you'll be writing in the future. When using this line:
DocumentReference taskref = fStore.collection("usersData").document(userId)
.collection("tasks").document(tskid);
You are creating a reference to that location. However, when using this line:
taskref.delete().addOnCompleteListener(/* ... */);
You are trying to delete a document that does not exist and this is because you didn't create it in the first place. If you need to delete a specific document, you need to know the ID. So the following lines of code will do the trick:
public void deleteTasks(View v) {
userId = mFirebaseAuth.getCurrentUser().getUid();
String tskid = "CQ45RKh8Ohd6DXjSQ8RO";
DocumentReference taskref = fStore.collection("usersData").document(userId)
.collection("tasks").document(tskid);
taskref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d("tag", "Task Deleted Successfully");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("tag", "Task Deletion Unsuccessful");
}
});
}
In order to delete that document, I have used the exact same ID that exists in the database.

how to prevent OnComplete fire when remove a not exist child or value

as the title. The OnCompleteListener will fire even when the child I remove does not exist. How can I prevent OnComplete (or OnSuccess ) fire when remove a not exist child ?
this is the code:
ROOT_REF.child("111").removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d("SSSSSSSSSSSSSSSSSSSS","onComplete");
}
});
note : the child "111" does not exist.
An onComplete listener fires when the state you set has been accomplished on the server. There is no way to change this behavior of the onComplete listener.
If you want to ensure that only a single user can remove a value, and that you know it is the current user, you should use a transaction. With a transaction you determine the new value of a node, based on its current value.
ROOT_REF.child("111").runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Object value = mutableData.getValue();
if (value == null) {
// Node doesn't exist
return Transaction.success(mutableData);
}
// Remove value and report transaction success
mutableData.setValue(null);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "postTransaction:onComplete:" + databaseError);
}
});
Note that:
A transaction's doTransaction method may fire multiple time, precisely when another user has modified the value already. For more on this, see Firebase runTransaction not working - MutableData is null.
Since transactions read the current value of the node, they only work when the user is online.

Firebase updating password (current pass and new pass)

I've been struggling about the change password functionality of my app. I am confused on how I can compare the current pass and store the new password thru firebase database.
Please don't be harsh on me on comments, educate me please. I did research first before asking and tried several times. Most of the tutorials I found are about updating data while clicking an item in listview. The reason why I use db to store users is because I am going to create 2 keys that identifies if user is student or professor.I just want to ask help how am I able to implement change of password.
ChangePassAccount.class
public class ChangePassAccount extends AppCompatActivity {
Button btnSave;
EditText cpass, npass;
String pass, newpass;
DatabaseReference dbPDF;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_change_pass_account);
dbPDF = FirebaseDatabase.getInstance().getReference("users").child("password");
cpass = (EditText)findViewById(R.id.currentpass);
npass = (EditText)findViewById(R.id.newpass);
btnSave = (Button) findViewById(R.id.btnsave);
btnSave.setBackgroundResource(R.drawable.button);
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pass = cpass.getText().toString();
newpass = npass.getText().toString();
}
});
}
}
i'll suggest you to using firebase auth to manage User Login or Changes password etc.. So maybe you only has to store user Data by UserInfo
this is a sample from Firebase-Manage User to change the user password
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String newPassword = "SOME-SECURE-PASSWORD";
user.updatePassword(newPassword)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User password updated.");
}
}
});
This is not a very technical answer but I ran into this problem in iOS recently.
There is a FirebaseAuth method named 'reauthenticate' that can be found here. This takes a credential that you create by asking for the user's password and getting the email from currentUser. If this returns successful you will know that password is correct. After reauthenticated you can call updatePassword with the new password.
As a suggestion you should not need to store the password separately in the database since Firebase will handle all this for you.
Hope this helps out, good luck!
You'd use a Firebase Database transaction for that. This gives you the current value, which you then compare against the old password. If they match, you return the new password.
Something like:
passwordRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
String password = mutableData.getValue(String.class);
if (password.equals(oldPassword) {
mutableData.setValue(newPassword);
return Transaction.success(mutableData);
}
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
Log.d(TAG, "passwordTransaction:onComplete:" + databaseError);
}
});
First you need to read the current password using single value event listener
pass = cpass.getText().toString();
newpass = npass.getText().toString();
dbPDF.addValueEventListener(addListenerForSingleValueEvent(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
String password = dataSnapshot.getValue(String.class);
if(password.equals(pass)){
dbPDF.setValue(newpass);
}else{
// show wrong pass dialog
}
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
Also make sure dbref is correct
String username = "helpmepls";
dbPDF = FirebaseDatabase.getInstance().getReference("users").child(username).child("password");

Categories

Resources