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)
根因分析
- 用户提前登出导致
userID为空:在sendVerificationEmail()方法中,发送验证邮件后立即调用mAuth.signOut(),此时FirebaseAuth的当前用户变为null。而checkIfUsernameExists()方法依赖从当前用户Uid获取的userID,直接触发空指针异常。 - 用户名检查逻辑错误:
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
相关产品推荐
相关产品推荐

