60

ここ数週間、MVP パターンをいじっていて、 a を開始してserviceにアクセスするためのコンテキストが必要になるところまで来ましたShared Preferences

MVP の目的はビューをロジックから分離することでcontextあり、その目的を無効にするPresenter可能性があることを読みました (これについて間違っている場合は修正してください)。

現在、次のような LoginActivity があります。

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();
    }
}

プレゼンター インターフェイス 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();
}

最後に、プレゼンター:

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() {
    }
}

ご覧のとおり、 からActivitymyにコンテキストを渡したPresenterので、 にアクセスできますShared Preferences。コンテキストをプレゼンターに渡すことを非常に心配しています。これは大丈夫ですか?それとも他の方法でやるべきですか?

編集 Jahnold の 3 番目の設定を実装

インターフェイスと実装はほとんどすべてなので無視しましょう。これinjectingで、Sharedpreference からプレゼンターへのインターフェイスになりました。これが私のコードです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()); }

    }
}

コンテキストを取得する方法は、MyApplication.java

アプリケーションが開始したら、次のコード行でこのオブジェクト グラフを作成します。

objectGraph = ObjectGraph.create(new AppModule(this));

これでいいですか?つまり、アクティビティからプレゼンターにコンテキストを渡す必要はなくなりましたが、アプリケーションのコンテキストはまだ持っています。

4

3 に答える 3

5

この質問は少し前に回答されました.MVPの定義がOPが彼のコードで使用したものであると仮定すると、@Jahnoldによる回答は本当に良いです.

ただし、MVP は高レベルの概念であり、MVP の原則に従って多くの実装が存在する可能性があることを指摘する必要があります。猫の皮を剥ぐ方法は複数あります。

MVP の別の実装があります。これは、Android のアクティビティは UI Elements ではなく、MVP プレゼンターとして指定さActivityれるという考えに基づいています。Fragmentこの構成では、MVP プレゼンターは に直接アクセスできますContext

ちなみに、前述の MVP の実装でも、プレゼンターでContextアクセスするためには使用しません。SharedPreferencesそれでも、ラッパー クラスを定義しSharedPreferencesてプレゼンターに挿入します。

于 2016-11-11T13:03:28.173 に答える
2

DB やネットワークなどのドメイン要素のほとんどは、コンテキストを構築する必要があります。View は Model に関する知識を持たないため、View で Thay を作成することはできません。その後、Presenter で作成する必要があります。それらは Dagger によって注入できますが、Context も使用しています。したがって、Context は Presenter xP で使用されます

ハックは、Presenter で Context を回避したい場合は、これらすべての Model オブジェクトを Context から作成し、保存しないコンストラクターを作成するだけでよいということです。しかし、私の意見では、それはばかげています。Android の新しい JUnit は Context にアクセスできます。

もう 1 つのハックは、コンテキストを null 可能にすることです。ドメイン オブジェクトには、コンテキストで null の場合にテスト インスタンスを提供するメカニズムが必要です。私もこのハックが好きではありません。

于 2017-03-03T15:52:44.100 に答える