如何在不使用Dagger的情况下使用MVP中的共享首选项并且不会导致Presenter与上下文相关?

我试图实现无匕首MVP(用于学习目的)。 但是我遇到了这个问题 – 我使用Repository patter从caching(Shared Preferences)或networking获取原始数据:

Shared Prefs| |<->Repository<->Model<->Presenter<->View Network| 

但是要把我的手放在共享首选项上,我必须把它放在某处

 presenter = new Presenter(getApplicationContext()); 

我使用onRetainCustomNonConfigurationInstance / getLastCustomNonConfigurationInstance对来保持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; } //... } 

那么如何在不使用Dagger的情况下使用MVP中的共享首选项,并且不会导致Presenter与上下文相关?

Solutions Collecting From Web of "如何在不使用Dagger的情况下使用MVP中的共享首选项并且不会导致Presenter与上下文相关?"

您的演示者不应该首先依赖于Context 。 如果您的演示者需要SharedPreferences ,则应在构造函数中将其传入
如果您的演示者需要一个Repository ,再次将其放入构造函数中 。 我强烈build议你看一下Google干净的代码会谈,因为他们很好地解释了为什么你应该使用一个合适的API。

这是适当的依赖pipe理,这将帮助您编写干净,可维护和可testing的代码。 无论你使用匕首,其他一些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); } } 

这个对象的创build可以通过使用工厂模式或者像Dagger这样的一些DI框架来简化,但是正如你上面所看到的,既不是Repository也不是你的演示者依赖于Context 。 如果你想提供你的实际的SharedPreferences只有他们的创build将取决于上下文。

您的存储库取决于一些api客户端和SharedPreferences ,您的演示者依赖于Repository 。 这两个类都可以轻松地通过向他们提供模拟对象来testing。

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

这是我如何做到的。 我有一个单独的“SharedPreferencesManager”类,将处理所有的读写操作共享prefs像下面

 public final class SharedPreferencesManager { private static final String MY_APP_PREFERENCES = "ca7eed88-2409-4de7-b529-52598af76734"; private static final String PREF_USER_LEARNED_DRAWER = "963dfbb5-5f25-4fa9-9a9e-6766bfebfda8"; ... // other shared preference keys private SharedPreferences sharedPrefs; private static SharedPreferencesManager instance; private SharedPreferencesManager(Context context){ //using application context just to make sure we don't leak any activities sharedPrefs = context.getApplicationContext().getSharedPreferences(MY_APP_PREFERENCES, Context.MODE_PRIVATE); } public static synchronized SharedPreferencesManager getInstance(Context context){ if(instance == null) instance = new SharedPreferencesManager(context); return instance; } public boolean isNavigationDrawerLearned(){ return sharedPrefs.getBoolean(PREF_USER_LEARNED_DRAWER, false); } public void setNavigationDrawerLearned(boolean value){ SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putBoolean(PREF_USER_LEARNED_DRAWER, value); editor.apply(); } ... // other shared preference accessors } 

然后,只要需要访问共享首选项,我就在相关的Presenter的构造函数中传递SharedPreferencesManager对象。 例如 :

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

希望这可以帮助!

您可以在Repository层使用Application上下文,而无需通过Presenter ,如此处所述 。 首先子类化你的应用程序类,并将其实例保存在一个静态variables中。

 public class MyApplication extends Application { private static context = null; public void onCreate(...) { context = this; ... } public static Context getContext() { return context; } } 

然后在AndroidManifest提及您的Application类名称,

 <application android:name=".MyApplication" ... > </application> 

现在,您可以使用MyApplication.context使用Repository中的Application上下文(SharedPreferences,SQLite数据库,networking访问)。