After register with Firebase phone number (sms), I can get user_id and friends list from user_id, etc. But after I exit from app, and then re-enter the app return null (FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();) I cannot not get Firebase user id (firebaseUser return null). implementation 'com.google.firebase:firebase-auth:21.0.1' Plz... How to solve a problem?
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) { // return null
DatabaseReference reference1 = FirebaseDatabase.getInstance().getReference("Users").child(firebaseUser.getUid());
reference1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NotNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
}
#Override
public void onCancelled(#NotNull DatabaseError databaseError) {
}
});
}
Firebase automatically restores the user credentials when you restart the app. This requires it to make a call to the server, amongst others to check whether the account was disabled. Since this call may take some time to complete, most likely it's still ongoing when you call FirebaseAuth.getInstance().getCurrentUser().
For this reason it's best to instead observe FirebaseAuth.instance.authStateChanges() as shown in the https://stackoverflow.com/collectives/google-cloud/articles/68104924/listen-for-authentication-state-in-android. This callback gets called first when the authentication check I mentioned has completed, so you can use that to respond to the restored sign-in:
auth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
Log.i("firebase", "AuthState changed to null");
}
else {
Log.i("firebase", "AuthState changed to "+firebaseAuth.getCurrentUser().getUid());
}
}
});
Related
My database consists of a collection called songs which has fields: artist, email, link and name. At the moment the email field in all documents is an empty string. Here is a pic of one of the entries.
Here is the query that I'm running in my android app:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registration);
firebaseAuth = FirebaseAuth.getInstance();
FirebaseFirestore db = FirebaseFirestore.getInstance();
TextView userinfo = (TextView)findViewById(R.id.link);
FirebaseUser userauth = firebaseAuth.getCurrentUser();
db.collection("songs").whereEqualTo("email",userauth.getEmail()).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>(){
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
// Document found in the offline cache
userinfo.setText("User found");
} else {
userinfo.setText("User not found");
}
}
});
}
The TextView is printing User found even though all the email entries are empty strings. The expected behavior is User not found.
If you only check if a Task is successful it doesn't mean that you get results. It means that your query is completed with no errors. If you need to know if the query returns the desired result, then you should check that in code:
if (task.isSuccessful()) {
QuerySnapshot snapshot = task.getResult();
if (snapshot.isEmpty()) {
userinfo.setText("User not found");
} else {
userinfo.setText("User found");
}
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
The "User not found" message will be set to your userinfo TextView.
I am creating a Journal app.
I am currently working on the functionality for if the user is already logged in—bypass the "get started/log in activities"
In the video I am watching to create a journal app, the instructor calls
mUser = firebaseAuth.getCurrentUser(); several times.
He calls it in onStart(), in onCreate() and in onAuthStateChanged(). I can understand why we might need to call it again in onAuthStateChanged(), but in this case, I'm just checking if the user is already logged in, so it shouldn't change from the user received in onCreate()
I removed it from onAuthStateChanged() and onStart() and everything is still working fine. However, I'm unsure if it will lead me to errors in the future. If anyone can confirm this, I would appreciate it.
Is there a reason why we need to call getCurrentUser() several times?
Thanks.
This is my full code for reference:
public class MainActivity extends AppCompatActivity {
Button getStarted;
private FirebaseUser mUser;
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener myListener;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference myCollectionRef = db.collection("Users");
#Override
protected void onCreate(Bundle savedInstanceState) {
firebaseAuth = FirebaseAuth.getInstance();
mUser = firebaseAuth.getCurrentUser();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getStarted = findViewById(R.id.btnGetStarted);
getStarted.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, LoginActivity.class));
finish();
}
});
myListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull #NotNull FirebaseAuth firebaseAuth) {
if(mUser != null){
//logged in
//I commented this out and everything is still working fine
//mUser = firebaseAuth.getCurrentUser();
String currentUserId = mUser.getUid();
myCollectionRef.whereEqualTo("userId", currentUserId).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable #org.jetbrains.annotations.Nullable QuerySnapshot value, #Nullable #org.jetbrains.annotations.Nullable FirebaseFirestoreException error) {
if(error != null){
Log.d("my_error", error.toString());
}
if(!value.isEmpty()){
for(QueryDocumentSnapshot snapshot : value){
JournalApi myJournalApi = new JournalApi();
myJournalApi.setUsername(snapshot.getString("username"));
myJournalApi.setId(snapshot.getString("userId"));
startActivity(new Intent(MainActivity.this, JournalList.class));
finish();
}
}
}
});
}else{
//not logged in
}
}
};
}
#Override
protected void onStart() {
super.onStart();
//I commented this out and everything is still working fine
//mUser = firebaseAuth.getCurrentUser();
firebaseAuth.addAuthStateListener(myListener);
}
#Override
protected void onPause() {
super.onPause();
if(firebaseAuth != null){
firebaseAuth.removeAuthStateListener(myListener);
}
}
}
While signing in is an active process, that your code triggers by calling one of the signInWith methods, maintaining the authentication state and restoring it on application restart are background processes that happen automatically when you use the Firebase SDK. This is great, because it means you don't have to write code to keep tokens valid, or to check if the user profile has changed or their account has been disabled.
It does mean however that you can't reliably cache the value of firebaseAuth.getCurrentUser() in a variable for much time. If you keep the value in a variable, and then the SDK updates the authentication state in the background, your code may not be looking at the correct value for firebaseAuth.getCurrentUser() anymore.
That's why you'll see more calls to firebaseAuth.getCurrentUser() than you might expect, and also why you'll see firebaseAuth.addAuthStateListener in places that want to get notified when the authentication state changed, like when the user is signed in or out by the SDK.
You've to call this method everytime you want to check the user's current session due the user's session can be changed from another service or method, if you don't call this method and just call once, you won't have the latest user's profile info, auth session, and such more.
I use addListenerForSingleValueEvent to add value into the child "code" of the current user, but instead the data duplicated.
Here is the database before the coding
This is the coding for the addListenerForSingleValueEvent
b4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mAuth = FirebaseAuth.getInstance();
mUser = mAuth.getCurrentUser();
final String UserId = mUser.getUid();
mReference = FirebaseDatabase.getInstance().getReference("Users");
final DatabaseReference currentUserId = mReference.child(UserId);
currentUserId.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
user.setCode(riasec1);
currentUserId.child(UserId).setValue(user);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
Here is the database after the coding is executedWhy is the whole user being duplicated instead of only value "code" inserted?
When you call
currentUserId.child(UserId).setValue(user);
you are saying "add WHOLE user in to node with name 'UserId'".
In general you are fetching WHOLE User, updating one field and updating again.
So when would you like to update a child without rewriting the entire object u should pass node name, e.g.
currentUserId.child(UserId).child("code").setValue(riasec1);
In this call you say:
find node with proper ID (UserId)
find node "code"
set new value (riasec1)
I'm currently working on a quiz app, where a user signs up with email and pw via firebase.
After the signup he shall pass a nickname which will be used in for a highscore.
So basically I want the app to add a these kind of user information, everytime a user signs up as shown in the attached picture.
In order to achieve this I used this code:
public class createNickname extends AppCompatActivity {
private static final String TAG = "createNickname";
private FirebaseDatabase mFirebaseDatabase;
private FirebaseAuth.AuthStateListener mAuthListener;
private EditText NicknameInput;
private Button NicknameReg;
private String Nickname, UserId;
private FirebaseAuth mAuth;
private String EmailEntry;
private DatabaseReference myref = mFirebaseDatabase.getInstance().getReference();
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_nickname);
NicknameInput = (EditText)findViewById(R.id.etNickname);
NicknameReg = (Button)findViewById(R.id.btsetNickname);
mAuth = FirebaseAuth.getInstance();
myref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange( DataSnapshot dataSnapshot ) {
String value = dataSnapshot.getValue(String.class);
Log.d(TAG, "value is: " + value);
}
#Override
public void onCancelled( DatabaseError databaseError ) {
Log.w(TAG, "Failed to read value.", databaseError.toException());
}
});
NicknameReg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick( View view ) {
Log.d(TAG, "onClick: Attempting to add object to database.");
String newNick = NicknameInput.getText().toString();
if (!newNick.equals("")) {
FirebaseUser user = mAuth.getCurrentUser();
UserId = user.getUid();
EmailEntry = user.getEmail();
myref.child("userlist").push().setValue(UserId);
myref.child("userlist").child(UserId).push().setValue(EmailEntry);
myref.child("userlist").child(UserId).push().setValue(0);
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
}
}
});
}
#Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
FirebaseUser currentUser = mAuth.getCurrentUser();
}
}
So the question is now, what did I do wrong?
A user is created in the authentication window in firebase, but the database is just not updated.
Did I target the database correctly? How do u decided which database you want to target?
These are my firebase security rules:
{
"rules": {
".read": false,
".write": false
}
}
Regarding the database nothing is happening if i get it right.
I get no error message what so ever.
First I would advice to add a completion callback to your code so you know when and if your writes to Firebase have failed/succeeded.
In your case you would get a permission denied error because your security rules are set to false -> nobody has permission to read/write to your database. Instead you could give each user permission to write to their own data like this:
{
"rules": {
"userlist": {
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
(See the documentation for more information)
For the above to work you will also have to change your code you are using to write to the database. Currently you are using push(). This generates a random id and you don't need (want) that here. Instead you can use setValue():
myref.child("userlist").push().setValue(UserId);
myref.child("userlist").child(UserId).child("email").setValue(EmailEntry);
myref.child("userlist").child(UserId).child("highscore").setValue(0);
You can also look at my answer here for a bit more information about this subject.
I am currently developing an android app that only requires the user to sign up once after pressing start. The next time the user opens the application, pressing start will redirect the user to the main game already.
I was able to do this using SharedPreferences. After signing up, I store a value called currentState and I use it to check if the user has already signed up. Here's the code:
final int currentState = sharedPreferences.getInt(USERSTATE_NUM_KEY,0);
if(currentState == 0 ) {
Intent i = new Intent(MainActivity.this, Main_Screen.class);
startActivity(i);
} else{
// Redirect user to tutorial page, then the map page.
}
Now I was asked to accomplish this again using Firebase since I've already stored the user data.
Here's my code so far just to try if it's going to the onDataChange but it doesn't and I'm not sure how to do it now. Here's my code so far:
final String currentUsername = sharedPreferences.getString(USERNAME_NUM_KEY, "");
final DatabaseReference userNameRef = rootReference.child("users");
startGame.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
userNameRef.orderByChild("username").equalTo(currentUsername)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
Log.v("TESTERR", "HELLO I EXIST LOL");
}
else{
Log.v("TESTERR", "NEW USER PAGE");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
Thank you!!!
This:
userNameRef.orderByChild("username").equalTo(currentUsername)
is a query it is like saying where username= currentUsername
The currentUsername is the logged in user, the datasnapshot is users.
So in your database you have:
users
userid
username: currentUsername
When you use if(dataSnapshot.exists()){ it checks the snapshot which is users and checks the where condition, if theys exists in the database then it will enter the if clause.
If the where condition does not exists in the database then it will enter the else.