简体   繁体   中英

Null pointer with Firebase auth. How to put listener to another class

Trying to implement firebase auth. It was working before but after refactoring no. So I tried to create authStateListener in a separate class and there I am checking the statement. MainActivity

IMainPresenter iMainPresenter;
        iMainPresenter = new MainPresenter();
        iMainPresenter.forwardInfoForLoginAuth(MainActivity.this);

In presenter

public class MainPresenter implements IMainPresenter{

    AuthStateListenerUtil authStateListenerUtil;

    public MainPresenter() {
        this.authStateListenerUtil = authStateListenerUtil;
    }

    @Override
    public void forwardInfoForLoginAuth(Activity mainActivity) {
        AuthStateListenerUtil authStateListenerUtils = new AuthStateListenerUtil();
        authStateListenerUtils.checkForAuthState(mainActivity);
    }
}

And the class which has to check the state of the user and in case that user is not logged in it has to show login window

public void checkForAuthState(final Activity mainActivity){
    Log.v("==========>", " IN CHECK FOR METHOD");

    new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            if (FirebaseUserUtil.currentUser != null) {
                //Create new user
                final String userName = FirebaseUserUtil.currentUser.getDisplayName();
                FirebaseUserUtil.getCurrentUserUid(FirebaseUserUtil.userUid)
                        .addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {

                            //the image is still the default one
                            HashMap<String, String> userMap = new HashMap<>();
                            userMap.put("name", userName);
                            userMap.put("image", "default");
                            userMap.put("thumb_image", "default");
                            userMap.put("status", "Your status is here...");
                            FirebaseUserUtil.getCurrentUserUid(FirebaseUserUtil.userUid).setValue(userMap);
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {}
                });

            } else {
                mainActivity.startActivityForResult(
                        AuthUI.getInstance()
                                .createSignInIntentBuilder()
                                .setAvailableProviders(Arrays.asList(
                                        new AuthUI.IdpConfig.EmailBuilder().build(),
                                        new AuthUI.IdpConfig.GoogleBuilder().build()))
                                .build(),
                        RC_SIGN_IN);
            }
        }
    };
}

I am trying to initialize all main queries in one class to avoid duplicating on each activity. In future I will refactor it to dagger2 but right now I am using regular classes. So thats the query class

public class FirebaseUserUtil {

   public static FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
   public static String currentUserUid = currentUser.getUid();

    public static DatabaseReference getCurrentUserUid(){
        return FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserUid);
    }

    static String getCurrentUserUidString(String uid){
        String currentUid = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserUid).toString();
        return currentUid;
    }

}

In logs it shows me tag "IN CHECK FOR METHOD" so I made a conclusion that threw presenter it finds this method but it crashes. Also, I thought that it might be a problem with firebase database. So I removed everything from there. So if I understand right if the table in firebase is empty after user login it has to create a new table with data. Also the problem is that error which I can see in logcat don't give me a link or information where is the mistake.

FATAL EXCEPTION: main
                                                                         Process: com.borisruzanov.russianwives, PID: 6777
                                                                         java.lang.NullPointerException: Attempt to invoke interface method 'void com.google.firebase.auth.FirebaseAuth$AuthStateListener.onAuthStateChanged(com.google.firebase.auth.FirebaseAuth)' on a null object reference
                                                                             at com.google.firebase.auth.zzi.run(Unknown Source)
                                                                             at android.os.Handler.handleCallback(Handler.java:751)
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                             at android.os.Looper.loop(Looper.java:154)
                                                                             at android.app.ActivityThread.main(ActivityThread.java:6119)
                                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

My App class

public class App extends Application{

    private DatabaseReference mUserDatabase;
    private FirebaseAuth mAuth;

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

        FirebaseDatabase.getInstance().setPersistenceEnabled(true);

        /* Picasso */

        Picasso.Builder builder = new Picasso.Builder(this);
        builder.downloader(new OkHttpDownloader(this, Integer.MAX_VALUE));
        Picasso built = builder.build();
        built.setIndicatorsEnabled(true);
        built.setLoggingEnabled(true);
        Picasso.setSingletonInstance(built);

        mAuth = FirebaseAuth.getInstance();

        if(mAuth.getCurrentUser() != null) {

            mUserDatabase = FirebaseDatabase.getInstance()
                    .getReference().child("Users").child(mAuth.getCurrentUser().getUid());

            mUserDatabase.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    if (dataSnapshot != null) {

                        mUserDatabase.child("online").onDisconnect().setValue(ServerValue.TIMESTAMP);

                    }

                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });

        }


    }


}

For me it looks like that the error is in Database not in code.

If your behavior it's the same for all user state changes you've to use "addAuthStateListener".

For AuthStateListener works you have to execute some of methods to authenticate ("signInWithEmailAndPassword", "createUserWithEmailAndPassword", ...).

The best way to implement a FirebaseAuth is keeping an instance in your Presenter or Interactor of that object and program the same code block for all:

FirebaseAuth mAuth;
public MainPresenter() {
    FirebaseAuth mAuth = FirebaseAuth.getInstance();
    mAuth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            /* 
             *  put your code here
             */
        }
    });
 }

Or addOnCompleteListener for each method of authentication (in this case signInWithEmailAndPassword).

 public void login(String email, String password){

    mAuth.signInWithEmailAndPassword(email, password)
                 .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    Log.d(getClass().getSimpleName(), "signInWithEmail:onComplete:" + task.isSuccessful());

                    if (task.isSuccessful()) {
                        Log.w(getClass().getSimpleName(), "signInWithEmail", task.getException());
                        FirebaseUser user = mAuth.getCurrentUser();
                        if (user!=null) {
                            listener.onResult(null, user);
                        }
                    } else {
                        listener.onResult(task.getException(), null);
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            listener.onResult(e, null);
        }
    });
  }

When you are using the floowing line of code:

new FirebaseAuth.AuthStateListener() {/* ... */}

It means that you are creating a new instance of AuthStateListener class but without assignin it to a variable.

So it gives you a NPE because you using addAuthStateListener() on an object that has the value of null . To solve this, just asign new FirebaseAuth.AuthStateListener() to you mAuth field and then use it wherever you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM