Ich habe seit ein paar Wochen mit dem MVP-Muster herum gespielt und bin zu dem Punkt gekommen, wo ich den Kontext brauche, um eine service
zu starten und auf Shared Preferences
zuzugreifen.Hat der Moderator, der die Aktivität/den Kontext kennt, eine schlechte Idee im MVP-Muster?
Ich habe gelesen, dass der Zweck der MVP den Blick von der Logik zu entkoppeln ist und diesen Zweck vereiteln können (korrigieren Sie mich, wenn ich das falsch bin) innerhalb eines Presenter
context
mit.
Derzeit habe ich eine LoginActivity, die etwa wie folgt aussieht:
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();
}
}
Presenter Schnittstelle 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();
}
Schließlich meine Presenter :
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() {
}
}
Wie Sie sehen können, habe ich den Kontext aus den Activity
in meine Presenter
nur so kann ich die Shared Preferences
zugreifen. Ich bin ziemlich besorgt darüber, den Kontext in meinen Moderator zu übertragen. Ist das eine gute Sache? Oder sollte ich es anders machen?
EDIT Implementiert Jahnold der 3. Präferenz
sie also die Schnittstelle und Implementierung ignorieren, weil es so ziemlich die ganze Sache. So, jetzt bin ich injecting
die Schnittstelle für die Sharedreference in meinem Presenter. Hier ist mein Code für die 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()); }
}
}
Die Art und Weise ich den Kontext von MyApplication.java
ist
Wenn die Anwendung beginnt, ich sicherstellen, dass dieses Objekt Graph mit dieser Codezeile zu erstellen:
objectGraph = ObjectGraph.create(new AppModule(this));
Ist das okay? Ich meine, ich muss jetzt nicht den Kontext von der Aktivität in meinen Moderator übertragen, aber ich habe immer noch Kontext der Anwendung.
Ich mag die letzte auch, aber mit Blick auf die Implementierung, würde ich noch Kontext brauchen, oder? Also muss ich in meinem DI-Modul irgendwo den richtigen Kontext angeben? Ich frage das, weil ich keine Ahnung habe, wie man diese Injektion einrichtet. Kann das Gleiche auch mit Diensten gemacht werden? –
Vergiss es, ich habe es herausgefunden. Arbeiten gut, aber ich bin mir nicht sicher, wie das hinter den Kulissen funktioniert. Ich werde meine Frage aktualisieren, um Ihnen zu zeigen, was ich getan habe, um die Injektion durchzuführen und lassen Sie mich wissen, wenn dies nicht optimal ist. –
Was Sie getan haben, sieht gut aus. Der Anwendungskontext ist jetzt vor dem Presenter verborgen, da er im SharedPreferencesRepository gekapselt ist. Der Präsentator weiß alles über das Repository. – Jahnold