Firebase 身份验证 getcurrentUser java.lang.NullPointerException

Firebase Auth getcurrentUser java.lang.NullPointerException

我是一名学生,正在使用 Firebase 开发 Android 应用程序。我一直在尝试设置 Firebase 身份验证,但我不断收到 null ptr 异常的错误。

  1. 用户进入 LoginActivity.java 屏幕使用 Google-Sign In API 登录并获取已通过 Firebase 验证

  2. 则用户进入下一个activity,MainActivity.java.

看起来像 MainActivity.java 中的代码:FirebaseUser user = firebaseAuth.getCurrentUser(); returns 是一个空值,我不知道如何避免这种情况!

这是我发现的相关跟踪:

FATAL EXCEPTION: main
 Process: joroze.com.roomifer, PID: 23176
 java.lang.RuntimeException: Unable to start activity ComponentInfo{joroze.com.roomifer/joroze.com.roomifer.MainActivity}: java.lang.NullPointerException
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
     at android.app.ActivityThread.access0(ActivityThread.java:135)
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
     at android.os.Handler.dispatchMessage(Handler.java:102)
     at android.os.Looper.loop(Looper.java:136)
     at android.app.ActivityThread.main(ActivityThread.java:5021)
     at java.lang.reflect.Method.invokeNative(Native Method)
     at java.lang.reflect.Method.invoke(Method.java:515)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643)
     at dalvik.system.NativeStart.main(Native Method)
  Caused by: java.lang.NullPointerException
     at joroze.com.roomifer.MainActivity.onCreate(MainActivity.java:126)
     at android.app.Activity.performCreate(Activity.java:5426)
     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1090)
     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
     at android.app.ActivityThread.access0(ActivityThread.java:135) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
     at android.os.Handler.dispatchMessage(Handler.java:102) 
     at android.os.Looper.loop(Looper.java:136) 
     at android.app.ActivityThread.main(ActivityThread.java:5021) 
     at java.lang.reflect.Method.invokeNative(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:515) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643) 
     at dalvik.system.NativeStart.main(Native Method) 

LoginActivity.java

public class LoginActivity extends AppCompatActivity implements
        GoogleApiClient.OnConnectionFailedListener,
        View.OnClickListener {

    private static final String TAG = "SignInActivity";
    private static final int RC_SIGN_IN = 9001;

    // [START declare_auth]
    private FirebaseAuth mAuth;
    // [END declare_auth]

    // [START declare_auth_listener]
    private FirebaseAuth.AuthStateListener mAuthListener;
    // [END declare_auth_listener]


    private GoogleApiClient mGoogleApiClient;
    private ProgressDialog mProgressDialog;

    /**
     * Id to identity READ_CONTACTS permission request.
     */
    private static final int REQUEST_READ_CONTACTS = 0;

    private DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);


        // Button listeners
        findViewById(R.id.sign_in_button).setOnClickListener(this);

        // [START configure_signin]
        // Configure sign-in to request the user's ID, email address, and basic
        // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
        // Configure Google Sign In
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();
        // [END configure_signin]





        // [START build_client]
        // Build a GoogleApiClient with access to the Google Sign-In API and the
        // options specified by gso.
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();
        // [END build_client]

        // [START initialize_auth]
        mAuth = FirebaseAuth.getInstance();
        // [END initialize_auth]

        // [START auth_state_listener]
        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in
                    Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
                } else {
                    // User is signed out
                    Log.d(TAG, "onAuthStateChanged:signed_out");
                }

            }
        };
        // [END auth_state_listener]


        // [START customize_button]
        // Set the dimensions of the sign-in button.
        SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
        signInButton.setSize(SignInButton.SIZE_STANDARD);
        // [END customize_button]


    }

    @Override
    public void onStart() {
        super.onStart();

        mAuth.addAuthStateListener(mAuthListener);

        OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
        if (opr.isDone()) {
            // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
            // and the GoogleSignInResult will be available instantly.
            Log.d(TAG, "Got cached sign-in");
            GoogleSignInResult result = opr.get();
            handleSignInResult(result);

        } else {
            // If the user has not previously signed in on this device or the sign-in has expired,
            // this asynchronous branch will attempt to sign in the user silently.  Cross-device
            // single sign-on will occur in this branch.
            showProgressDialog();
            opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
                @Override
                public void onResult(GoogleSignInResult googleSignInResult) {
                    hideProgressDialog();
                    handleSignInResult(googleSignInResult);
                }
            });

        }
    }


    // [START onActivityResult]
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            handleSignInResult(result);
        }
    }
    // [END onActivityResult]

    // [START handleSignInResult]
    private void handleSignInResult(GoogleSignInResult result) {
        Log.d(TAG, "handleSignInResult:" + result.isSuccess());

        if (result.isSuccess()) {
            // Signed in successfully, show authenticated UI.
            GoogleSignInAccount acct = result.getSignInAccount();
            firebaseAuthWithGoogle(acct);

            Intent nextActivity = new Intent(this, MainActivity.class);
            startActivity(nextActivity);

        } else {
            Log.d(TAG, "Currently signed out");
            // Signed out, show unauthenticated UI.
        }
    }
    // [END handleSignInResult]

    // [START signIn]
    private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }
    // [END signIn]


    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // An unresolvable error has occurred and Google APIs (including Sign-In) will not
        // be available.
        Log.d(TAG, "onConnectionFailed:" + connectionResult);
        Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
    }


    private void showProgressDialog() {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setMessage("Loading...");
            mProgressDialog.setIndeterminate(true);
        }

        mProgressDialog.show();
    }

    private void hideProgressDialog() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.hide();
        }
    }


    @Override
    public void onClick(View v) {
        signIn();
    }


    // [START on_stop_remove_listener]
    @Override
    public void onStop() {
        super.onStop();
        if (mAuthListener != null) {
            mAuth.removeAuthStateListener(mAuthListener);
        }
    }
    // [END on_stop_remove_listener]

    // [START auth_with_google]
    private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
        Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
        // [START_EXCLUDE silent]
        showProgressDialog();
        // [END_EXCLUDE]

        AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithCredential", task.getException());
                            Toast.makeText(LoginActivity.this, "Authentication failed.",
                                    Toast.LENGTH_SHORT).show();
                        }
                        // [START_EXCLUDE]
                        hideProgressDialog();
                        // [END_EXCLUDE]
                    }
                });
    }
    // [END auth_with_google]

}

MainActivity.java

    public class MainActivity extends AppCompatActivity
            implements NavigationView.OnNavigationItemSelectedListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, CreateGroupDialogFragment.CreateGroupDialogListener {

        private static final String TAG = "SignInActivity";

        FirebaseManageJSON fbmjson = new FirebaseManageJSON(this);

        private FirebaseAuth mAuth;
        private FirebaseAuth.AuthStateListener mAuthListener;

        FirebaseUser mCurrentUser;

        GoogleApiClient mGoogleApiClient;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mAuth = FirebaseAuth.getInstance();

            mAuthListener = new FirebaseAuth.AuthStateListener() {
                @Override
                public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                    FirebaseUser user = firebaseAuth.getCurrentUser();
                    if (user != null) {
                        // Currently signed in
                        mCurrentUser = user;

                        clientUser = new User(mCurrentUser.getUid(), mCurrentUser.getDisplayName(), mCurrentUser.getEmail());
                        writeNewUser(clientUser);

                    } else {
                        signOut();
                    }
                }
            };


            // [START configure_signin]
            // Configure sign-in to request the user's ID, email address, and basic
            // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
            GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                    .requestEmail()
                    .build();
            // [END configure_signin]

            // [START build_client]
            // Build a GoogleApiClient with access to the Google Sign-In API and the
            // options specified by gso.
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                    .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                    .build();
            // [END build_client]

            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    showCreateGroupDialog();
                }
            });


            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);


            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                    this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            drawer.setDrawerListener(toggle);

            toggle.syncState();

            NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
            navigationView.setNavigationItemSelectedListener(this);

            View hView = navigationView.getHeaderView(0);

            TextView userNameView = (TextView) hView.findViewById(R.id.usernameView);
            TextView emailView = (TextView) hView.findViewById(R.id.emailView);
            ImageView profileImageView = (ImageView) hView.findViewById(R.id.profileImageView);

            if (mCurrentUser.getDisplayName() != null)
                userNameView.setText(mCurrentUser.getDisplayName());

            if (mCurrentUser.getEmail() != null)
                emailView.setText(mCurrentUser.getEmail());

            if (mCurrentUser.getPhotoUrl().toString() != null)
                Glide.with(this).load(mCurrentUser.getPhotoUrl().toString()).into(profileImageView);

            drawer.openDrawer(GravityCompat.START);
        }

            @Override
            public void onBackPressed() {
                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                if (drawer.isDrawerOpen(GravityCompat.START)) {
                    drawer.closeDrawer(GravityCompat.START);
                } else {
                    // User should not need to go to the previous activity this way
                    //super.onBackPressed();
                }
            }


            @Override
            public boolean onCreateOptionsMenu (Menu menu){
                // Inflate the menu; this adds items to the action bar if it is present.
                getMenuInflater().inflate(R.menu.main, menu);

                return true;
            }


            @Override
            public boolean onOptionsItemSelected (MenuItem item){

                String message = "Roomifer is awesome!";
                Intent share = new Intent(Intent.ACTION_SEND);
                share.setType("text/plain");
                share.putExtra(Intent.EXTRA_TEXT, message);

                // Handle action bar item clicks here. The action bar will
                // automatically handle clicks on the Home/Up button, so long
                // as you specify a parent activity in AndroidManifest.xml.
                int id = item.getItemId();

                //noinspection SimplifiableIfStatement
                if (id == R.id.action_menu) {
                    startActivity(Intent.createChooser(share, "Share using Messenger"));
                    return true;
                }

                return super.onOptionsItemSelected(item);
            }


            @SuppressWarnings("StatementWithEmptyBody")
            @Override
            public boolean onNavigationItemSelected (MenuItem item){
                // Handle navigation view item clicks here.
                int id = item.getItemId();

                if (id == R.id.nav_camera) {
                    // Handle the camera action
                } else if (id == R.id.nav_share) {

                } else if (id == R.id.nav_manage) {

                } else if (id == R.id.nav_signout) {
                    signOut();
                } else if (id == R.id.nav_deleteAccount) {
                    revokeAccess();
                }

                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                drawer.closeDrawer(GravityCompat.START);
                return true;

            }


            @Override
            public void onConnected (@Nullable Bundle bundle){

            }

            @Override
            public void onConnectionSuspended ( int i){
                mGoogleApiClient.connect();
            }

            @Override
            public void onConnectionFailed (@NonNull ConnectionResult connectionResult){
                Log.d(TAG, "Connection FAILED!");
            }

        public void signOut() {


            // Firebase sign out
            FirebaseAuth.getInstance().signOut();

            // Google sign out
            Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
                    new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status status) {

                            // Firebase sign out
                            mAuth.signOut();

                            if (status.isSuccess())
                                Log.d(TAG, "Log Out successful!");
                            else
                                Log.d(TAG, "Log Out failed!");

                            // finish this activity, and go back to the sign-in activity screen
                            finish();
                        }
                    });
        }

        public void revokeAccess() {
            Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
                    new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status status) {

                            // Firebase sign out
                            mAuth.signOut();

                            deleteAccount(clientUser);

                            if (status.isSuccess())
                                Log.d(TAG, "Revoke successful!");
                            else
                                Log.d(TAG, "Revoke failed!");

                            // finish this activity, and go back to the sign-in activity screen
                            finish();
                        }
                    });
        }

        protected void onStart() {
            super.onStart();

            mAuth.addAuthStateListener(mAuthListener);

            //Snackbar snackbar = Snackbar.make(this.findViewById(R.id.mainSnackBarView), "Signed in as " + clientUser.getUserName(), Snackbar.LENGTH_SHORT);
            //snackbar.show();

        }

        protected void onStop() {
            super.onStop();
            if (mGoogleApiClient.isConnected()) {
                mGoogleApiClient.disconnect();
            }

            if (mAuthListener != null) {
                mAuth.removeAuthStateListener(mAuthListener);
            }
        }

    }

提前致谢!

MainActivityonCreate()方法中,需要初始化mAuth:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mAuth = FirebaseAuth.getInstance(); // <== ADD THIS

    ...
}

更新:

MainActivity中,mCurrentUser为空,因为AuthStateListener还没有运行。侦听器直到 onStart() 运行 秒才注册。将 onCreate() 中使用 mCurrentUser 的代码移动到侦听器中。