1

I have my MainActivity in which I handle the logout. Problem is after I log out, the app crashes in verifyUserExistance() at line:

String userID = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();

Which gives :

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.google.firebase.quickstart.auth, PID: 8459 java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at com.google.firebase.quickstart.auth.social.Main_Chat_Activity$3.lambda$null$1$Main_Chat_Activity$3(Main_Chat_Activity.java:372) at com.google.firebase.quickstart.auth.social.-$$Lambda$Main_Chat_Activity$3$87CwjFnoJAhucBGNsLP_MxK833o.onComplete(Unknown Source:2) at com.google.android.gms.tasks.zzj.run(com.google.android.gms:play-services-tasks@@17.2.0:4) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7050) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)

Below is the code I use:

@Override
protected void onStart() {
    super.onStart();
    usersRef.child(mAuth.getCurrentUser().getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            if (!snapshot.hasChild("name"))
            {
                sendUserToLoginActivity();
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {

        }
    });
    if (mAuth == null || currentUser == null || mAuth.getCurrentUser().getUid() == null ){
        finish();
        sendUserToLoginActivity();
    }
    else {
        if(mAuth.getCurrentUser().getProviderId() == "google.com"){
            user.setmGoogleSignInClient(mGoogleSignInClient);
        }
        user.setMauth(mAuth);
        if (loginOutFlag>-1)
            verifyUserExistence();
    }
    checkLocation();
    if (isNew!=null)
    {
        if (isNew.equals("true")){
            sendUserToSettingsActivity();
        }
    }
}

The method verifyUserExistance is;

 private void verifyUserExistence() {
    if (!verified && loginOutFlag > -1) {
        String currentUserID = mAuth.getCurrentUser().getUid();
        try {


            rootRef.child("Users").child(currentUserID).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                    if (dataSnapshot.child("name").exists()) {
                        loginOutFlag = 1;
                        Toast.makeText(Main_Chat_Activity.this, "Welcome" + dataSnapshot.child("name").getValue().toString(), Toast.LENGTH_SHORT).show();
                        Log.w("Reportname:", dataSnapshot.child("name").getValue().toString());
                        Calendar cal = Calendar.getInstance();
                        final String timeNDate = cal.getTime().toString();
                        HashMap<String, Object> profileMap = new HashMap<>();
                        profileMap.put("connection", timeNDate);
                        rootRef.child("Users").child(currentUserID).updateChildren(profileMap)
                                .addOnCompleteListener(task ->
                                {
                                    if (task.isSuccessful()) {
                                        Toast.makeText(Main_Chat_Activity.this, "Success ", Toast.LENGTH_SHORT).show();
                                        verified = true;
                                        FirebaseMessaging.getInstance().getToken()
                                                .addOnCompleteListener(task13 -> {
                                                    String userID = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();
                                                    if (!task13.isSuccessful()) {
                                                        Log.w("FCM", "Fetching FCM registration token failed", task13.getException());
                                                        return;
                                                    }

                                                    // Get new FCM registration token
                                                    String deviceToken = task13.getResult();

                                                    // Log and toast

                                                    Log.d("FCM", deviceToken);
                                                    Toast.makeText(Main_Chat_Activity.this, deviceToken, Toast.LENGTH_SHORT).show();
                                                    final int[] no = {0};
                                                    DatabaseReference tokens = usersRef.child(userID).child("device_tokens");
                                                    ValueEventListener valueEventListener = new ValueEventListener() {
                                                        @Override
                                                        public void onDataChange(@NonNull DataSnapshot snapshot) {
                                                            no[0] = (int) snapshot.getChildrenCount();
                                                        }

                                                        @Override
                                                        public void onCancelled(@NonNull DatabaseError error) {

                                                        }
                                                    };
                                                    tokens.addListenerForSingleValueEvent(valueEventListener);
                                                    String devName = "device" + no[0];
                                                    String token = deviceToken.split(":")[1];
                                                    usersRef.child(userID).child("device_tokens").child(devName)
                                                            .setValue(token)
                                                            .addOnCompleteListener(task12 -> {
                                                                if (task12.isSuccessful()) {
                                                                    Toast.makeText(Main_Chat_Activity.this, "Token updated succesfully.", Toast.LENGTH_LONG).show();
                                                                }
                                                            });

                                                });
                                    } else {
                                        String errorMSG = Objects.requireNonNull(task.getException()).toString();
                                        //user.setMauth(null);
                                        Toast.makeText(Main_Chat_Activity.this, "Error : " + errorMSG, Toast.LENGTH_SHORT).show();
                                    }

                                });

                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            });
        }
        catch (Exception e)
        {
            Log.d("EXCEPTION", e.toString());
        }
    }


}

and this is how I handle the logout;

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    super.onOptionsItemSelected(item);

    if (item.getItemId() == R.id.main_logout_option) {
        updateUserStatus("offline");
        String currentUserID = mAuth.getCurrentUser().getUid();

        rootRef.child("Users").child(currentUserID).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                if (dataSnapshot.child("name").exists()) {

                    Calendar cal = Calendar.getInstance();
                    final String timeNDate = cal.getTime().toString();
                    HashMap<String, Object> profileMap = new HashMap<>();
                    profileMap.put("connection", timeNDate);
                    rootRef.child("Users").child(currentUserID).updateChildren(profileMap)
                            .addOnCompleteListener(task ->
                            {
                                if (task.isSuccessful()) {
                                    loginOutFlag = -1;
                                } else {
                                    String errorMSG = Objects.requireNonNull(task.getException()).toString();
                                    Toast.makeText(Main_Chat_Activity.this, "This error : " + errorMSG, Toast.LENGTH_SHORT).show();
                                }
                                mGoogleSignInClient.signOut().addOnCompleteListener(task1 -> {
                                    if (task1.isSuccessful()){
                                        mAuth.signOut(); // very important if you are using firebase.
                                        LoginManager.getInstance().logOut();
                                        sendUserToLoginActivity();
                                        finish();
                                    }
                                });
                            });
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

        sendUserToLoginActivity();
    }

    if (item.getItemId() == R.id.main_settings_option) {
        sendUserToSettingsActivity();
    }
    if (item.getItemId() == R.id.main_find_friends_option) {
        sendUserToFindFriendsActivity();
    }
    return true;
}
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
James Ele
  • 43
  • 6

1 Answers1

2

Problem is after I log out, the app crashes:

at line String userID = Objects.requireNonNull(mAuth.getCurrentUser()).getUid()

When you log out, the mAuth objct becomes null. So calling getCurrentUser() on a such an object, instead of returning a FirebaseUser object, it will return null, hence the presence of the NullPointerExcepetion.

Returns the currently signed-in FirebaseUser or null if there is none.

So the solution for your problem is to wait for the asynchronous operation to finish, and right after that to sign out, otherwise, you'll always get NullPointerExcepetion.

Here is an example of you can wait until the data is finished loading from the Realtime Database:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • See the issue is if mAuth is null then in the onStart() method it should send me to loginActivity since I use `if (mAuth == null || currentUser == null || mAuth.getCurrentUser().getUid() == null ){ finish(); sendUserToLoginActivity(); } else { if(mAuth.getCurrentUser().getProviderId() == "google.com"){ user.setmGoogleSignInClient(mGoogleSignInClient); } user.setMauth(mAuth); if (loginOutFlag>-1) verifyUserExistence(); }` and yet it doesn't. The problem really stems from here. Any other options? – James Ele May 13 '21 at 12:57
  • If `mAuth` is null in the onStart(), then it means that the user is not loggedin. You should check for that before doing further operations with such an object. Unfortunately, another option other than waiting for the data, there isn't. Try to wait for the data and tell me if it works. – Alex Mamo May 13 '21 at 14:18
  • But mAuth IS null (or should be), because I sign out. Yet in `onStart` it seems like it isn't and that's why it wrongfully calls `verifyUserExistance`. – James Ele May 13 '21 at 19:23
  • Have you tried to sign out, after the async operation is finished? – Alex Mamo May 13 '21 at 19:35
  • I think there might be more to it. See, when I click on logout, the UI changes to the LoginActivity, and only then does it crash. But that doesn't make sense. How can an activity that I have called `finish()` crash after another has started?? – James Ele May 13 '21 at 19:35
  • You were right. I shouldn't have added that line there but before I started the async task of retrieving and updating on Firebase. I still don't understand though, why it runs AFTER I log out. – James Ele May 14 '21 at 04:25
  • It runs, as it takes time for the operation to complete. That's the reason why you get that behavior. – Alex Mamo May 14 '21 at 06:37