[英]Android MVP: safe use Context in Presenter
在我的應用程序中,我使用ContentProvider
並使用LoaderManager.LoaderCallbacks<Cursor>.
片段(查看)
public class ArticleCatalogFragment extends BaseFragment
implements ArticleCatalogPresenter.View,
LoaderManager.LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return onCreateArticleCatalogLoader(args);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
data.registerContentObserver(new LoaderContentObserver(new Handler(), loader));
updateUI(data);
}
private Loader onCreateArticleCatalogLoader(Bundle args) {
int categoryId = args.getInt(CATEGORY_ID);
Loader loader = new ArticleCatalogLoader(this.getActivity(), categoryId);
return loader;
}
}
從MVP的角度來看,我需要:
主持人
public class ArticleCatalogPresenter extends BasePresenter
implements LoaderManager.LoaderCallbacks<Cursor> {
View view;
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return onCreateArticleCatalogLoader(args);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
data.registerContentObserver(new LoaderContentObserver(new Handler(), loader));
view.updateUI(data);
}
private Loader onCreateArticleCatalogLoader(Bundle args) {
int categoryId = args.getInt(CATEGORY_ID);
Loader loader = new ArticleCatalogLoader(context, categoryId); // need Context
return loader;
}
interface View {
updateUI(Cursor data)
}
}
所以,我需要Presenter中的上下文。
有一些細微差別:
主持人知道上下文 - 這很糟糕,Presenter不應該知道Android。
在Presenter中使用Context可能會導致內存泄漏。
我現在擔心如何避免內存泄漏等問題,以及如何在Presenter中最好地傳遞Context,使用Application Context或Activity / Fragment?
向Presenter添加上下文並不好,因為演示者負責業務邏輯。 要處理上下文,您需要讓Fragment / Activities在接口的幫助下使用Callbacks,這將說明在處理視圖時activity / fragment需要執行哪些操作。 片段/活動負責提供上下文。
例:
interface BaseContract {
interface BaseView {
//Methods for View
void onDoSomething();
}
interface BasePresenter {
void doSomething();
}
}
class BaseMainPresenter implements BaseContract.BasePresenter {
BaseContract.BaseView view;
BaseMainPresenter(BaseContract.BaseView view) {
this.view = view;
}
@Override
public void doSomething() {
if (view != null)
view.onDoSomething();
}
}
class DemoClass implements BaseContract.BaseView {
//Create object of Presenter
/****
* Example :
* BaseMainPresenter baseMainPresenter = new BaseMainPresenter(this);
*/
@Override
public void onDoSomething() {
//Deal with Context here.
}
}
只是不要將您的演示者注冊為Android特定的回調目標(例如BroadcastReceiver
, LoaderManager.LoaderCallbacks
等)。 處理View(片段或活動)中的回調方法,並將所有相關數據傳遞給演示者。
如果您需要創建對象的Context
,請讓您的視圖創建此對象(因為它具有對Context
的引用)。 在您的情況下,電話
Loader loader = new ArticleCatalogLoader(context, categoryId)
應該重構
view.createLoaderForCategory(categoryId)
像這樣的代碼
Loader loader = new ArticleCatalogLoader(context, categoryId);
導致不可測試的代碼。 您應該避免在代碼中創建“業務”對象,並讓其他人為您執行此操作(任何DI框架,如Dagger 2都是比自己處理它更好的選擇)
話雖如此,你的問題是DI很久以前解決的問題。 您是否需要任何對象的全新實例? 使用Provider
Provider
是“提供”對象實例的對象。 所以沒有
Loader loader = new ArticleCatalogLoader(context, categoryId);
您將擁有
Loader loader = loaderProvider.get(categoryId);
所以你唯一需要的是這樣的事情:
public class ArticleCatalogPresenter ... {
...
private final Provider<Loader> loaderProvider;
public ArticleCatalogPresenter(Provider<Loader> loaderProvider, ...) {
this.loaderProvider = loaderProvider;
...
}
private Loader onCreateArticleCatalogLoader(Bundle args) {
int categoryId = args.getInt(CATEGORY_ID);
Loader loader = loaderProvider.get(categoryId); // no context needed anymore!
return loader;
}
}
public class ArticleCatalogPresenter extends BasePresenter implements LoaderManager.LoaderCallbacks<Cursor> { View view; ... private Loader onCreateArticleCatalogLoader(Bundle args) { int categoryId = args.getInt(CATEGORY_ID); Loader loader = new ArticleCatalogLoader(context, categoryId); // need Context return loader; } }
因此,您希望Presenter中的context
構建ArticleCatalogLoader
的新實例。 對?
如果是這樣,請通過構造函數將實例傳遞給Presenter 。 因此,當您要構建Presenter對象時,在Activity或DI容器中,執行以下操作:
ArticleCatalogPresenter articleCatalogPresenter=new ArticleCatalogPresenter(articleCatalogView,new ArticleCatalogLoader(context,categoryId));
這樣,您的Presenter將不依賴於context
並且將完全可測試。
關於您對內存泄漏的關注,您可以通過在View中監聽onStop()
然后調用Presenter中的相應方法來取消任何網絡請求或context
相關任務,從而輕松避免這種context
。
我編寫了一個MVP庫 ,它可以節省大量MVP所需的樣板,以防止內存泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.