如何在没有Dagger的MVP中使用共享首选项并且不会导致Presenter依赖于上下文?

Mar*_*och 36 mvp dependencies android dependency-injection sharedpreferences

我正在尝试在没有Dagger的情况下实现MVP(用于学习目的).但我遇到了问题 - 我使用Repository模式从缓存(共享首选项)或网络获取原始数据:

Shared Prefs| 
            |<->Repository<->Model<->Presenter<->View
     Network|
Run Code Online (Sandbox Code Playgroud)

但要把手放在共享首选项上,我必须把它放在某个地方

presenter = new Presenter(getApplicationContext());
Run Code Online (Sandbox Code Playgroud)

我使用onRetainCustomNonConfigurationInstance/ getLastCustomNonConfigurationInstancepair来保持Presenter"保留".

public class MyActivity extends AppCompatActivity implements MvpView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...
        presenter = (MvpPresenter) getLastCustomNonConfigurationInstance();

        if(null == presenter){
            presenter = new Presenter(getApplicationContext());
        }

        presenter.attachView(this);
    }

    @Override
    public Object onRetainCustomNonConfigurationInstance() {
        return presenter;
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

那么如何在没有Dagger的MVP中使用共享首选项并且不会导致Presenter依赖于上下文?

Dav*_*jak 72

您的演示者不应该首先Context依赖.如果您的演示需要SharedPreferences,你应该通过他们构造.
如果您的演示者需要a Repository,请再次将其放入构造函数中.我强烈建议您观看谷歌清洁代码会谈,因为他们非常好地解释了为什么要使用适当的API.

这是正确的依赖关系管理,它将帮助您编写干净,可维护且可测试的代码.无论你使用匕首,其他一些DI工具,还是自己提供物品都是无关紧要的.

public class MyActivity extends AppCompatActivity implements MvpView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SharedPreferences preferences = // get your preferences
        ApiClient apiClient = // get your network handling object
        Repository repository = new Repository(apiClient, preferences);
        presenter = new Presenter(repository);
    }
}
Run Code Online (Sandbox Code Playgroud)

这个对象创建可以通过使用工厂模式或一些DI框架(如匕首)来简化,但正如您在上面看到的那样,Repository您的演示者也不会依赖于Context.如果您想提供实际的,SharedPreferences他们的创建将取决于上下文.

您的存储库取决于某些API客户端SharedPreferences,您的演示者依赖于Repository.通过向它们提供模拟对象,可以轻松地测试这两个类.

没有任何静态代码.没有任何副作用.

  • 如果您的代码依赖于存储接口而不是存储实现(如SharedPreferences),那会更好吗?拥有一个接口可以使演示者真正与框架无关,因为只有存储接口的实现才能了解Android框架 (5认同)
  • @NicolásCarrasco当然可以根据需要添加更多抽象.这个答案主要是为了说明如何不依赖于上下文,我不想过于复杂化. (3认同)
  • @DavidMedenjak 我是 MVP 的新手,请帮助我理解这个解决方案是如何帮助我的..因为在我看来,`presenter` 依赖于 `respository` 而 `repository` 依赖于 `shared pref` ......这不意味着 ` Presenter` 依赖于 `shared pref`(间接地)......或者我缺少核心 (3认同)
  • @eRaisedToX那是对的.但是,演示者现在可以使用模拟的存储库进行测试,并且不依赖于Android框架.您也可以随时从SharedPreferences切换到其他一些基于文件的设置,而无需更改演示者.它是关于清洁代码,易于测试,并且单一责任可以打印 (2认同)