【问题标题】:Why is firebase authentication returning null?为什么firebase身份验证返回null?
【发布时间】:2021-09-27 12:31:53
【问题描述】:

我正在尝试实现 Firebase 匿名身份验证并从应用程序获取唯一 ID,但它一直运行到空 UID 错误。我使用以下代码块进行匿名登录并获取用户的 UID:

// Firebase Anonymous Auth
        firebaseAuth = FirebaseAuth.getInstance();
        firebaseUser = firebaseAuth.getCurrentUser();

        if(firebaseUser == null){
            firebaseAuth.signInAnonymously()
                    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            if (task.isSuccessful()) {
                                // Sign in success, update UI with the signed-in user's information
                                firebaseUser = firebaseAuth.getCurrentUser();
                                currentUserID = firebaseUser.getUid();
                            }
                        }
                    });
        }

我按照 Firebase 文档中的说明进行操作,但由于某种原因无法正常工作。每当我尝试引用 currentUserID 时,它都会返回错误:Attempt to invoke virtual method 'void com.example.rllauncher.TouchData.setUniqueID(java.lang.String)' on a null object reference

我一直在尝试缩小问题的范围,但大多数匿名登录的实现都是这样完成的,所以我无法缩小问题的根源。究竟是什么导致了这里的问题?

这是完整的活动代码:

public class ButtonPress extends AppCompatActivity implements View.OnClickListener {
    private Button button;
    private DisplayMetrics displaymetrics;
    private RelativeLayout loOPenArea;
    private Handler mHandler = new Handler();
    private String currentUSerID;
    String TASK_NAME = "ButtonPress";

    FirebaseAuth mAuth = FirebaseAuth.getInstance();
    FirebaseUser mFirebaseUser = mAuth.getCurrentUser();
    String mCurrentUserID = mFirebaseUser != null
            ? mFirebaseUser.getUid()
            : null;

    FirebaseAuth.AuthStateListener mAuthListener = new FirebaseAuth.AuthStateListener() {
        @NonNull
        @Override
        public void onAuthStateChanged(FirebaseAuth auth) {
            mFirebaseUser = auth.getCurrentUser();
            if (mFirebaseUser == null) {
                // user has been confirmed to be signed out
                // reset state, detach listeners, etc
                mCurrentUserID = null;
                return;
            }
            // user has been confirmed to be signed in
            mCurrentUserID = mFirebaseUser.getUid();
            currentUSerID = mCurrentUserID;
            // do something, refresh UI, etc
        }
    };
    private VelocityTracker mVelocityTracker = null;
    public static final DatabaseReference databaseReference = FirebaseDatabase.getInstance("https://pragya-datacollector.firebaseio.com").getReference();


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

        button = findViewById(R.id.my_button);
        button.setClickable(true);
        button.setOnClickListener(this);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent i = new Intent(ButtonPress.this, IntermediateActivity.class);
                i.putExtra("type", "failure");
                if (!ButtonPress.this.isFinishing())
                { ButtonPress.this.startActivity(i);
                ButtonPress.this.finish();
                }
            }
        }, 10000);

        // Wait until the first layout to get button size and placement to compute x/y placement range.
        button.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                button.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                // Capture width and x/y placement ranges here
                final Button button = (Button) findViewById(R.id.my_button);
                displaymetrics = new DisplayMetrics();
                getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
                loOPenArea = (RelativeLayout) findViewById(R.id.open_area_press);

                // Button will have a horizontal margin from zero to the width of its parent less
                // the width of the button less the initial left side of the button which is likely
                // to be the initial margin.
                int buttonMaxXMargin = loOPenArea.getWidth() - button.getWidth() - button.getLeft();
                // Similar for the vertical placement.
                int buttonMaxYMargin = loOPenArea.getHeight() - button.getHeight() - button.getTop();

                int leftMargin = new Random().nextInt(buttonMaxXMargin);
                int topMargin = new Random().nextInt(buttonMaxYMargin);

                ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) button.getLayoutParams();
                p.setMargins(leftMargin, topMargin, 0, 0);

                button.setLayoutParams(p);
            }
        });


    }

    @Override
    public void onClick(View v) {
        Vibrator x = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            x.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
        } else {
            x.vibrate(500);
        }
        Intent i = null;
        switch (v.getId()) {

            case R.id.my_button:
                i = new Intent(ButtonPress.this, IntermediateActivity.class);
                i.putExtra("type", "null");
                if (!ButtonPress.this.isFinishing())
                { ButtonPress.this.startActivity(i);
                    ButtonPress.this.finish();
                }
                break;
        }
    }
    public boolean dispatchTouchEvent(MotionEvent event) {

        TouchData touchData = null;

        int index = event.getActionIndex();
        int pointerId = event.getPointerId(index);
        List<Float> xTraj = new ArrayList<Float>();
        List<Float> yTraj = new ArrayList<Float>();


        final int X = (int) event.getRawX();
        final int Y = (int) event.getRawY();
        xTraj.add(event.getX());
        yTraj.add(event.getY());
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                xTraj.add(event.getX());
                yTraj.add(event.getY());
                if(mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                }
                else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                // Add a user's movement to the tracker.
                mVelocityTracker.addMovement(event);
                break;

            case MotionEvent.ACTION_UP:
                mVelocityTracker.recycle();

                float centreX = button.getX() + button.getWidth()  / 2;
                float centreY = button.getY() + button.getHeight() / 2;

                long eventDuration = event.getEventTime() - event.getDownTime();

                touchData.setUniqueID(currentUSerID);
                touchData.setTaskName(TASK_NAME);
                touchData.setTouchDuration(eventDuration);
                touchData.setxTrajectory(xTraj);
                touchData.setyTrajectory(yTraj);
                touchData.setxVelocity(VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
                touchData.setyVelocity(VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId));
                touchData.setTargetX(centreX);
                touchData.setTargetY(centreY);
                databaseReference.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {
                        databaseReference.setValue(touchData);
                    }

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

                    }
                });
                break;
            case MotionEvent.ACTION_MOVE:
                xTraj.add(event.getX());
                yTraj.add(event.getY());
                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1);

                break;

            case MotionEvent.ACTION_CANCEL:
                mVelocityTracker.recycle();
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public void onBackPressed() {
        finish();
        IntermediateActivity.visitCount = 0;
        Intent k = new Intent(ButtonPress.this, MainActivity.class);
        k.putExtra("type", "null");
        startActivity(k);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mAuth.addAuthStateListener(mAuthListener);
        if (mFirebaseUser == null) {
            mAuth.signInAnonymously()
                    .addOnFailureListener(new OnFailureListener() {
                        @NonNull
                        @Override
                        public void onFailure(Exception ex) {
                            // TODO: Handle exceptions!
                            Log.e("TAG", "Failed to sign in anonymously: " +  ex.getMessage());
                        }
                    });
        }


    }

    @Override
    protected void onStop() {
        super.onStop();
        mAuth.removeAuthStateListener(mAuthListener);
    }
}

【问题讨论】:

    标签: android firebase firebase-authentication uniqueidentifier


    【解决方案1】:

    我认为你应该初始化一次task.isSuccessful()

    firebaseAuth = FirebaseAuth.getInstance();
    
    if(firebaseAuth.getCurrentUser() == null){
       firebaseAuth.signInAnonymously().addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
           @Override
           public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                      // Sign in success, update UI with the signed-in user's information
                      final FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
                      currentUserID = firebaseUser.getUid();
                }
           }
       });
    }
    

    更新:

    你不能在方法之外初始化它们。

    public class ButtonPress extends AppCompatActivity implements View.OnClickListener {
        private Button button;
        private DisplayMetrics displaymetrics;
        private RelativeLayout loOPenArea;
        private Handler mHandler = new Handler();
        private String currentUSerID;
        String TASK_NAME = "ButtonPress";
    
       FirebaseAuth mAuth; //Just variable, dont do anything
       FirebaseUser mFirebaseUser;//Just variable, dont do anything
       String mCurrentUserID;//Just variable, dont do anything
    

    【讨论】:

    • @RavishJha 您可以查看更新后的答案。
    【解决方案2】:

    问题是由竞争条件引起的。身份验证是一种异步操作,这意味着某些数据可能尚未准备好使用。重要的是,如果在onStart/onCreate 中使用全局状态(如firebaseUser),如果该用户退出、其令牌被撤销或活动登录用户发生更改,则会给您带来麻烦,因为它将指向过时的信息。

    在您的问题中,我假设您的代码类似于:

    // top of file
    FirebaseAuth firebaseAuth;
    FirebaseUser firebaseUser;
    String currentUserID;
    
    // ...
    
    // Firebase Anonymous Auth
    firebaseAuth = FirebaseAuth.getInstance();
    firebaseUser = firebaseAuth.getCurrentUser();
    
    if (firebaseUser == null) {
        firebaseAuth.signInAnonymously()
            .addOnCompleteListener(/* ... */)
    } else {
        currentUserId = firebaseUser.getCurrentUser().getUid();
    }
    
    TouchData data = new TouchData();
    data.setUniqueID(currentUserID); // <-- `null` exception here
    

    这是因为signInAnonymously 进程是异步的。当调用TouchData.setUniqueID(currentUserID) 时,在登录过程完成之前它仍然是null

    您还应该确保适当地处理任何异常,不要只是默默地忽略它们。

    if (firebaseUser == null) {
        firebaseAuth.signInAnonymously()
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        firebaseUser = task.getResult().getUser();
                        currentUserID = firebaseUser.getUid();
                    } else {
                        // TODO: Handle exceptions!
                        Exception ex = task.getException();
                        Log.e(TAG, "Failed to sign in anonymously: " +  ex.getMessage());
                    }
                }
            });
    }
    

    如果您的代码依赖于有效的用户会话,您应该改用AuthStateListener。此侦听器将在多种情况下触发,例如在用户登录后。使用它来附加点击处理程序、更新 UI 等。

    FirebaseAuth mAuth = FirebaseAuth.getInstance();
    FirebaseUser mFirebaseUser = mAuth.getCurrentUser();
    String mCurrentUserID = mFirebaseUser != null
        ? mFirebaseUser.getUid()
        : null;
    
    AuthStateListener mAuthListener = new AuthStateListener() {
        @NonNull
        @Override
        public void onAuthStateChanged(FirebaseAuth auth) {
            mFirebaseUser = auth.getCurrentUser();
            if (user == null) {
                // user has been confirmed to be signed out
                // reset state, detach listeners, etc
                mCurrentUserID = null;
                return;
            }
    
            // user has been confirmed to be signed in
            mCurrentUserID = user.getUid();
            // do something, refresh UI, etc
        }
    }
    
    // in onStart
    mAuth.addAuthStateListener(mAuthListener);
    if (mFirebaseUser == null) {
        mAuth.signInAnonymously()
            .addOnFailureListener(new OnFailureListener() {
                @NonNull
                @Override
                public void onFailure(Exception ex) {
                    // TODO: Handle exceptions!
                    Log.e(TAG, "Failed to sign in anonymously: " +  ex.getMessage());
                }
            });
    }
    
    // in onStop
    mAuth.removeAuthStateListener(mAuthListener);
    

    如果您的onAuthStateChanged 逻辑开始失控,请将其逻辑拆分为onAuthSignedInonAuthSignedOut 方法:

    AuthStateListener mAuthListener = new AuthStateListener() {
        @NonNull
        @Override
        public void onAuthStateChanged(FirebaseAuth auth) {
            if (auth.getCurrentUser() != null) {
                onAuthSignedIn(auth);
            } else {
                onAuthSignedOut(auth);
            }
        }
    }
    
    public void onAuthSignedIn(FirebaseAuth auth) {
    
    }
    
    public void onAuthSignedOut(FirebaseAuth auth) {
    
    }
    

    【讨论】:

    • 我进行了更改,但仍然遇到同样的错误。我还在问题中添加了完整的活动代码。
    猜你喜欢
    • 2021-12-27
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 2018-12-09
    相关资源
    最近更新 更多