Ho giocato per qualche settimana con lo schema MVP e sono giunto al punto in cui ho bisogno di un contesto per avviare uno service
e accedere allo Shared Preferences
.Il presentatore che ha conoscenza dell'attività/contesto è una cattiva idea nel pattern MVP?
Ho letto che lo scopo di MVP è quello di disaccoppiare la vista dalla logica e avendo context
all'interno di un Presenter
può sconfiggere questo scopo (correggetemi se sbaglio su questo).
Attualmente, ho un LoginActivity che sembra qualcosa di simile:
LoginActivity.java
public class LoginActivity extends Activity implements ILoginView {
private final String LOG_TAG = "LOGIN_ACTIVITY";
@Inject
ILoginPresenter mPresenter;
@Bind(R.id.edit_login_password)
EditText editLoginPassword;
@Bind(R.id.edit_login_username)
EditText editLoginUsername;
@Bind(R.id.progress)
ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
MyApplication.getObjectGraphPresenters().inject(this);
mPresenter.setLoginView(this, getApplicationContext());
}
@Override
public void onStart() {
mPresenter.onStart();
ButterKnife.bind(this);
super.onStart();
}
@Override
public void onResume() {
mPresenter.onResume();
super.onResume();
}
@Override
public void onPause() {
mPresenter.onPause();
super.onPause();
}
@Override
public void onStop() {
mPresenter.onStop();
super.onStop();
}
@Override
public void onDestroy() {
ButterKnife.unbind(this);
super.onDestroy();
}
@OnClick(R.id.button_login)
public void onClickLogin(View view) {
mPresenter.validateCredentials(editLoginUsername.getText().toString(),
editLoginPassword.getText().toString());
}
@Override public void showProgress() { mProgressBar.setVisibility(View.VISIBLE); }
@Override public void hideProgress() {
mProgressBar.setVisibility(View.GONE);
}
@Override public void setUsernameError() { editLoginUsername.setError("Username Error"); }
@Override public void setPasswordError() { editLoginPassword.setError("Password Error"); }
@Override public void navigateToHome() {
startActivity(new Intent(this, HomeActivity.class));
finish();
}
}
Presentatore interfaccia ILoginPresenter.java
public interface ILoginPresenter {
public void validateCredentials(String username, String password);
public void onUsernameError();
public void onPasswordError();
public void onSuccess(LoginEvent event);
public void setLoginView(ILoginView loginView, Context context);
public void onResume();
public void onPause();
public void onStart();
public void onStop();
}
Infine, il mio presentatore :
LoginPresenterImpl.java
public class LoginPresenterImpl implements ILoginPresenter {
@Inject
Bus bus;
private final String LOG_TAG = "LOGIN_PRESENTER";
private ILoginView loginView;
private Context context;
private LoginInteractorImpl loginInteractor;
public LoginPresenterImpl() {
MyApplication.getObjectGraph().inject(this);
this.loginInteractor = new LoginInteractorImpl();
}
/**
* This method is set by the activity so that way we have context of the interface
* for the activity while being able to inject this presenter into the activity.
*
* @param loginView
*/
@Override
public void setLoginView(ILoginView loginView, Context context) {
this.loginView = loginView;
this.context = context;
if(SessionUtil.isLoggedIn(this.context)) {
Log.i(LOG_TAG, "User logged in already");
this.loginView.navigateToHome();
}
}
@Override
public void validateCredentials(String username, String password) {
loginView.showProgress();
loginInteractor.login(username, password, this);
}
@Override
public void onUsernameError() {
loginView.setUsernameError();
loginView.hideProgress();
}
@Override
public void onPasswordError() {
loginView.setPasswordError();
loginView.hideProgress();
}
@Subscribe
@Override
public void onSuccess(LoginEvent event) {
if (event.getIsSuccess()) {
SharedPreferences.Editor editor =
context.getSharedPreferences(SharedPrefs.LOGIN_PREFERENCES
.isLoggedIn, 0).edit();
editor.putString("logged_in", "true");
editor.commit();
loginView.navigateToHome();
loginView.hideProgress();
}
}
@Override
public void onStart() {
bus.register(this);
}
@Override
public void onStop() {
bus.unregister(this);
}
@Override
public void onPause() {
}
@Override
public void onResume() {
}
}
Come potete vedere, ho passato il contesto dal Activity
nel mio Presenter
solo così posso accedere al Shared Preferences
. Sono abbastanza preoccupato di passare il contesto al mio presentatore. È una cosa giusta da fare? O dovrei farlo in un altro modo?
EDIT Implementato di Jahnold terza preferenza
Quindi cerchiamo di ignorare l'interfaccia e l'implementazione in quanto è praticamente l'intera cosa. Quindi ora sono injecting
l'interfaccia per Sharedpreference nel mio presentatore. Ecco il mio codice per il AppModule
AppModule.java
@Module(library = true,
injects = {
LoginInteractorImpl.class,
LoginPresenterImpl.class,
HomeInteractorImpl.class,
HomePresenterImpl.class,
}
)
public class AppModule {
private MyApplication application;
public AppModule(MyApplication application) {
this.application = application;
}
@Provides
@Singleton
public RestClient getRestClient() {
return new RestClient();
}
@Provides
@Singleton
public Bus getBus() {
return new Bus(ThreadEnforcer.ANY);
}
@Provides
@Singleton
public ISharedPreferencesRepository getSharedPreferenceRepository() { return new SharedPreferencesRepositoryImpl(application.getBaseContext()); }
}
}
Il modo in cui ricevo il contesto è da MyApplication.java
Quando inizia l'applicazione, faccio in modo di creare questo grafico Oggetto con questa riga di codice:
objectGraph = ObjectGraph.create(new AppModule(this));
Va bene? Voglio dire che ora non devo passare il contesto dall'attività al mio presentatore, ma ho ancora il contesto dell'applicazione.
Mi piace anche l'ultimo, ma guardando l'implementazione, avrei ancora bisogno di un contesto giusto? Quindi, all'interno del mio modulo DI, devo specificare da qualche parte il contesto corretto? Lo chiedo perché non ho idea di come impostare questa iniezione. Inoltre, si può fare lo stesso con i servizi? –
Non importa, l'ho capito. Funzionando bene, ma non sono sicuro di come funzioni dietro le quinte. Aggiornerò la mia domanda per mostrarti cosa ho fatto per eseguire l'iniezione e fammi sapere se questo non è ottimale. –
Quello che hai fatto sembra a posto. Il contesto dell'applicazione è ora nascosto da Presenter perché è incapsulato all'interno del SharedPreferencesRepository. Tutto ciò che il presentatore conosce è il repository. – Jahnold