0

According to this post and some other blog posts, It is bad to have Activity Context in a presenter in an MVP android app. What if one of the method in the presenter requires an Activity context, how can I remove the Activity context in the presenter and still have the presenter does the job it needs to get done?

In this Activity, it calls the method firebaseAuthWithGoogle in the presenter. The presenter is initialized by passing the activity, view and FirebaseAuth to the constructor.

public class GoogleSignInActivity extends AppCompatActivity implements
        GoogleApiClient.OnConnectionFailedListener, View.OnClickListener, GoogleSignInView {
    private static final String TAG = "SignInActivity";
    private static final int RC_SIGN_IN = 9001;

    private SignInButton mSignInButton;

    private GoogleApiClient mGoogleApiClient;

    // Firebase instance variables
    private FirebaseAuth mFirebaseAuth;

    private GoogleSignInPresenter googleSignInPresenter;

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

        mSignInButton = (SignInButton) findViewById(R.id.btn_sign_in);
        mSignInButton.setOnClickListener(this);

        // Configure Google Sign In
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        // Initialize FirebaseAuth
        mFirebaseAuth = FirebaseAuth.getInstance();

        googleSignInPresenter = new GoogleSignInPresenter(this, this, mFirebaseAuth);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_sign_in:
                googleSignInPresenter.onSignInClick();
                break;
            default:
                return;
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                GoogleSignInAccount account = result.getSignInAccount();
                googleSignInPresenter.firebaseAuthWithGoogle(account);
            } else {
                Log.e(TAG, "Google Sign-In failed.");
            }
        }
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.d(TAG, "onConnectionFailed:" + connectionResult);
        Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void startSignInIntent() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }

    @Override
    public void startMainActivity() {
        startActivity(new Intent(GoogleSignInActivity.this, MainActivity.class));
        finish();
    }


}

The method firebaseAuthWithGoogle in this presenter requires the Activity context in the addOnCompleteListener.

public class GoogleSignInPresenter {
    public static final String TAG = "GoogleSignInPresenter";

    private GoogleSignInView googleSignInView;
    private FirebaseAuth firebaseAuth;
    private GoogleSignInActivity googleSignInActivity;

    public GoogleSignInPresenter(GoogleSignInActivity googleSignInActivity, GoogleSignInView googleSignInView, FirebaseAuth firebaseAuth) {
        this.googleSignInActivity = googleSignInActivity;
        this.googleSignInView = googleSignInView;
        this.firebaseAuth = firebaseAuth;
    }

    public void onSignInClick() {
        googleSignInView.startSignInIntent();
    }


    public void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
        Log.d(TAG, "firebaseAuthWithGooogle:" + acct.getId());
        AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
        firebaseAuth.signInWithCredential(credential)
                .addOnCompleteListener(googleSignInActivity, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithCredential", task.getException());
                        } else {
                            googleSignInView.startMainActivity();
                        }
                    }
                });
    }
}
s-hunter
  • 24,172
  • 16
  • 88
  • 130

1 Answers1

2

I'm fairly certain that you can just remove the activity instance e.g.

.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
                    if (!task.isSuccessful()) {
                        Log.w(TAG, "signInWithCredential", task.getException());
                    } else {
                        googleSignInView.startMainActivity();
                    }
                }
            });

Read this: https://developers.google.com/android/guides/tasks

Charlie Niekirk
  • 1,015
  • 1
  • 10
  • 15
  • thx, nice find, but if I want this listener to be activity scoped so it will be removed in the onStop, I will still need the activity instance. This is just an example when I need the activity in the presenter. I am not sure what to do if an activity is required in the presenter for it to function. – s-hunter Oct 11 '17 at 12:53