You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase注册调用checkIfUsernameExists报空指针异常求助

Firebase注册时调用checkIfUsernameExists()出现NullPointerException问题解决

问题描述

尝试将用户凭据(用户名、邮箱)添加到Firebase实时数据库时,点击注册按钮调用firebaseMethods.checkIfUsernameExists()方法时触发空指针异常。

错误信息

FATAL EXCEPTION: main
                 Process: com.example.movies4u, PID: 25475
                 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.firebase.auth.FirebaseUser.getUid()' on a null object reference
                    at com.example.movies4u.Utils.FirebaseMethods.checkIfUsernameExists(FirebaseMethods.java:47)
                    at com.example.movies4u.activity_register$1$1.onDataChange(activity_register.java:200)
                    at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
                    at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
                    at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
                    at android.os.Handler.handleCallback(Handler.java:873)
                    at android.os.Handler.dispatchMessage(Handler.java:99)
                    at android.os.Looper.loop(Looper.java:224)
                    at android.app.ActivityThread.main(ActivityThread.java:7081)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:928)

根因分析

  1. 用户提前登出导致userID为空:在sendVerificationEmail()方法中,发送验证邮件后立即调用mAuth.signOut(),此时FirebaseAuth的当前用户变为null。而checkIfUsernameExists()方法依赖从当前用户Uid获取的userID,直接触发空指针异常。
  2. 用户名检查逻辑错误:checkIfUsernameExists()方法中遍历dataSnapshot.child(userID).getChildren(),仅在当前用户节点下查找,正确逻辑应遍历所有用户节点检查用户名是否重复。

解决方案

1. 修正用户名重复检查逻辑

修改FirebaseMethods中的checkIfUsernameExists()方法,遍历所有用户节点:

public boolean checkIfUsernameExists(String username, DataSnapshot dataSnapshot){
    // 获取所有用户节点
    DataSnapshot usersSnapshot = dataSnapshot.child(mContext.getString(R.string.dbname_users));
    for (DataSnapshot ds : usersSnapshot.getChildren()) {
        User user = ds.getValue(User.class);
        if (user != null && StringManipulation.expandUsername(user.getUsername()).equals(username)) {
            return true;
        }
    }
    return false;
}

2. 调整注册流程,避免提前登出

在sendVerificationEmail()中,不要立即登出用户,待数据库写入操作完成后再处理:

private void sendVerificationEmail() {
    FirebaseUser currentUser = mAuth.getCurrentUser();
    if (currentUser != null) {
        currentUser.sendEmailVerification().addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                btnRegister.setEnabled(true);
                pb.setVisibility(View.GONE);
                Toast.makeText(activity_register.this, "验证邮件已发送至您的邮箱", Toast.LENGTH_SHORT).show();
                // 暂时不登出,等待数据库操作完成后执行
            } else {
                btnRegister.setEnabled(true);
                pb.setVisibility(View.GONE);
                Toast.makeText(getApplicationContext(), "哎呀!发送验证邮件失败", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3. 确保userID正确传递

在AuthStateListener中直接从当前用户获取Uid,并传递给数据库操作方法:

// 在AuthStateListener的onAuthStateChanged方法中
if (user != null) {
    String userID = user.getUid(); // 直接从当前用户获取Uid
    myRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if(firebaseMethods.checkIfUsernameExists(username, dataSnapshot)){
                append = myRef.push().getKey().substring(3,10);
                Log.d(TAG, "onDataChange: 用户名已存在。为名称追加随机字符串: " + append);
            }
            username = username + append;
            // 传递userID到addNewUser方法
            firebaseMethods.addNewUser(email, username, userID);
            Toast.makeText(activity_register.this, "注册成功", Toast.LENGTH_SHORT).show();
            // 数据库写入完成后再登出
            mAuth.signOut();
            finish();
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Toast.makeText(activity_register.this, "操作失败", Toast.LENGTH_SHORT).show();
        }
    });
}

同时修改addNewUser()方法,接收userID参数:

public void addNewUser(String email, String username, String userID){
    User user=new User(email,username);
    if(userID!=null)
    {
        myRef.child(mContext.getString(R.string.dbname_users))
                .child(userID)
                .setValue(user).addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void unused) {
                        Log.d(TAG, "用户已添加");
                        Toast.makeText(mContext, "用户已添加", Toast.LENGTH_SHORT).show();
                    }
                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d(TAG, "用户添加失败");
                        Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });

        UserAccountSettings settings = new UserAccountSettings(username, username);

        myRef.child(mContext.getString(R.string.dbname_user_account_settings))
                .child(userID)
                .setValue(settings);
    }
    else {
        Log.d(TAG, "用户对象为空");
    }
}

关键注意事项

  • 避免在数据库操作完成前登出用户,确保所有写入操作执行完毕后再修改用户认证状态。
  • 检查用户名重复时,必须遍历所有用户节点,而非当前用户的私有节点。
  • 优先从FirebaseAuth的当前用户实例获取Uid,避免依赖可能为空的全局变量。

内容的提问来源于stack exchange,提问作者Nithin reddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:05:15