Android Firebase 注销应用程序在我注销后崩溃

Posted

技术标签:

【中文标题】Android Firebase 注销应用程序在我注销后崩溃【英文标题】:Android Firebase logout app crashes AFTER I logout 【发布时间】:2021-08-03 17:13:08 【问题描述】:

我有我在其中处理注销的 MainActivity。问题是我注销后,应用程序在verifyUserExistance() 处崩溃:

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

这给出了:

E/androidRuntime: 致命异常: main 进程:com.google.firebase.quickstart.auth,PID:8459 java.lang.NullPointerException 在 java.util.Objects.requireNonNull(Objects.java:203) 在 com.google.firebase.quickstart.auth.social.Main_Chat_Activity$3.lambda$null$1$Main_Chat_Activity$3(Main_Chat_Activity.java:372) 在 com.google.firebase.quickstart.auth.social.-$$Lambda$Main_Chat_Activity$3$87CwjFnoJAhucBGNsLP_MxK833o.onComplete(未知来源:2) 在 com.google.android.gms.tasks.zzj.run(com.google.android.gms:play-services-tasks@@17.2.0:4) 在 android.os.Handler.handleCallback(Handler.java:873) 在 android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:214) 在 android.app.ActivityThread.main(ActivityThread.java:7050) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)

下面是我使用的代码:

@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();
        
    

方法verifyUserExistance是;

 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());
        
    



这就是我处理注销的方式;

 @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;

【问题讨论】:

【参考方案1】:

问题是我注销后,应用程序崩溃:

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

当您注销时,mAuth 对象变为null。因此在这样的对象上调用getCurrentUser(),而不是返回FirebaseUser 对象,它将返回null,因此存在NullPointerExcepetion。

返回当前登录的 FirebaseUser,如果没有则返回 null。

因此,解决您的问题的方法是等待异步操作完成,然后立即退出,否则,您将始终得到 NullPointerExcepetion。

这是一个示例,您可以等到从实时数据库中加载完数据:

How to return DataSnapshot value as a result of a method?

【讨论】:

看到问题是如果 mAuth 为空,那么在 onStart() 方法中它应该将我发送到 loginActivity,因为我使用了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&gt;-1) verifyUserExistence(); ,但它没有。问题真的出自这里。还有其他选择吗? 如果mAuth在onStart()中为null,则表示用户未登录。在对此类对象进行进一步操作之前,您应该检查这一点。不幸的是,除了等待数据之外,没有其他选择。尝试等待数据并告诉我它是否有效。 但 mAuth 为空(或应该为空),因为我退出了。然而在onStart 中,它似乎不是,这就是它错误地调用verifyUserExistance 的原因。 您是否尝试在异步操作完成后退出? 我认为可能还有更多。看,当我单击注销时,UI 更改为 LoginActivity,然后它才会崩溃。但这没有意义。我称为finish() 的活动如何在另一个活动开始后崩溃??

以上是关于Android Firebase 注销应用程序在我注销后崩溃的主要内容,如果未能解决你的问题,请参考以下文章

注销后清除 Firebase 持久性

注销Firebase经过身份验证的用户后写入Firestore

当我使用重新加载功能时,Firebase Auth 会注销我吗?

Firebase Auth - 更新用户的电子邮件后,Firebase Auth 会注销用户

auth.logout 在我的应用程序中无法使用 firebase facebook 身份验证

使用用户的UID发送Firebase云消息