Android MVP中的模型需要上下文
在android中使用MVP时,我需要使用模型中的活动上下文来获取所有已安装应用程序的列表。在遵循MVP模式的同时,访问上下文的正确方法是什么,或者其他实现相同目的的方法是什么 以下是课程: Main Activity.java Main Presenter.java 公共类MainPresenter扩展了BasePresenter{Android MVP中的模型需要上下文,android,mvp,Android,Mvp,在android中使用MVP时,我需要使用模型中的活动上下文来获取所有已安装应用程序的列表。在遵循MVP模式的同时,访问上下文的正确方法是什么,或者其他实现相同目的的方法是什么 以下是课程: Main Activity.java Main Presenter.java 公共类MainPresenter扩展了BasePresenter{ MainModel model; public void onSendButtonClick() { model.getListO
MainModel model;
public void onSendButtonClick() {
model.getListOfAllApps();
}
@Override
public void addView(MainView view) {
super.addView(view);
model = new MainModel();
}
}
Main Model.java
在
getPackageManager().QueryInputActivities(mainIntent,0)
中存在问题。如何在没有任何上下文的情况下执行此操作。基本上,您有以下选项:
1) 始终将上下文
传递给模型。无论Android中发生什么事件,您总是可以使用某种上下文(并且您的代码仅在响应事件时调用)
2) getApplicationContext()
并将其存储在静态变量中以备将来使用
存在以下问题:
活动
是一个上下文
,但如果存储指向某个活动的链接,则会出现内存泄漏。例如,当屏幕旋转时,会重新创建活动。
传递给广播接收者的上下文和其他类型的上下文也是一样的。它们都有一个生存期,而这个生存期不是模型所需要的
您的应用程序可能被Android终止并重新启动。在这种情况下,某些全局(静态)变量可能被设置为null。也就是说,除非您的应用程序碰巧向它们写入了内容,否则它们将为null。特别是,在某个重启场景中,指向应用程序上下文的静态变量可能会变为null。这样的问题很难测试。我回答了一个类似的问题,您可能想问这个问题我也来看看。不过,我会详细说明我认为你可以如何解决这个问题
使用应用程序类中的静态上下文
这种方法可以工作,但我不喜欢。它使测试更加困难,并将代码耦合在一起
public class App extends Application {
private static Context context;
public static Context getContext() {
return context;
}
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
然后在主模型中:
public class MainModel {
public List<String> getListOfAllApps(){
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> pkgAppsList = App.getContext().getPackageManager().queryIntentActivities(mainIntent, 0);
List<String> results = new ArrayList<>();
for (ResolveInfo app : pkgAppsList) {
results.add(app.resolvePackageName);
}
return results;
}
}
在单独的类中抽象细节
虽然最后一个选项没有违反MVP的规则,但它感觉不太对,因为获取包列表并不是真正的视图操作。我的首选选项是在接口/类后面隐藏上下文的使用
创建一个类PackageModel
(或您喜欢的任何名称):
最后,在您的活动中:
public class MainActivity extends BaseActivity implements MainView {
//..
@Override
public List<String> getListOfAllApps(){
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> pkgAppsList = getPackageManager().queryIntentActivities(mainIntent, 0);
List<String> results = new ArrayList<>();
for (ResolveInfo app : pkgAppsList) {
results.add(app.resolvePackageName);
}
return results;
}
//..
}
public class MainActivity extends BaseActivity implements MainView {
private MainPresenter presenter;
private void createPresenter() {
PackageModel packageModel = new PackageModel(this);
presenter = new MainPresenter(packageModel);
presenter.addView(this);
}
}
现在,上下文的使用对演示者是隐藏的,它可以在不了解Android的情况下继续进行。这被称为构造函数注入。如果您使用依赖项注入框架,它可以为您构建所有依赖项
如果你想,你可以为PackageModel创建一个接口,但我认为这并不是真的必要,因为像Mockito这样的模拟框架可以创建一个存根而不使用接口。你没有应用程序类吗?我有应用程序类。但是如何使用它。你是说在应用程序类?问题是根据模式,我们不应该在模型中使用任何android特定的类/对象。一点也不。只需在onCreate(…)中创建applicationContext即可和使用itI我有一个MainActivity、一个MainPresenter和一个MainModel类。现在我需要访问模型中的上下文。在oncreate of activity中使用applicationcontext有什么用?@MD您完全没有在这里使用MVP来分离关注点的意义。因为模型包含业务逻辑,所以它应该是框架无关的,这意味着它不应该具有direct依赖于Android特定对象,如ContextAs所说,它只是隐藏了依赖关系,这更糟糕。在同一个线程上非常好,因为它使依赖关系非常清晰。我发现单例和隐藏依赖关系非常好。我只需对第3点做一个小的调整,将PackageModel作为一个接口,并使getListOfAllApps()它的第一个方法很糟糕。只是删除第一个方法。它绝对是错误的。演示者和模型应该是纯java。接口是真正的方式。@阿米齐亚拉蒂确实不是最好的方法,但我提到它来显示人们在移动到更好的选项之前可能会考虑什么。@ Jannod在你的第三个解决方案中,你是否合作?N将PackageModel命名为MVP模型?如果是这样,那么在MainActivity中创建PackageModel实例会在视图和模型之间创建链接,对吗?但据我所知,MVP模式中视图和模型之间不应该有任何链接。我是MVP主题的新手,我不了解这一点。您不应该在presenter和model中使用上下文。此代码不会被删除table.@AmirZiarati,我需要在模型中获取本地字符串context.getString(R.string…)。如果不使用context作为模型构造函数的参数,或者根本不使用context,我如何实现这一点?@Thracian只需使用视图层中的context从资源中获取它,并将其作为字符串依赖项发送到模型层。
public interface MainView {
List<String> getListOfAllApps();
}
public class MainActivity extends BaseActivity implements MainView {
//..
@Override
public List<String> getListOfAllApps(){
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> pkgAppsList = getPackageManager().queryIntentActivities(mainIntent, 0);
List<String> results = new ArrayList<>();
for (ResolveInfo app : pkgAppsList) {
results.add(app.resolvePackageName);
}
return results;
}
//..
}
public class MainPresenter extends BasePresenter {
public void onSendButtonClick(){
view.getListOfAllApps();
}
}
public class PackageModel {
private Context context;
public PackageModel(Context context) {
this.context = context;
}
public List<String> getListOfAllApps(){
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> pkgAppsList = context.getPackageManager().queryIntentActivities(mainIntent, 0);
List<String> results = new ArrayList<>();
for (ResolveInfo app : pkgAppsList) {
results.add(app.resolvePackageName);
}
return results;
}
}
public class MainPresenter extends BasePresenter {
private PackageModel packageModel;
public MainPresenter(PackageModel packageModel) {
this.packageModel = packageModel;
}
public void onSendButtonClick(){
packageModel.getListOfAllApps();
}
}
public class MainActivity extends BaseActivity implements MainView {
private MainPresenter presenter;
private void createPresenter() {
PackageModel packageModel = new PackageModel(this);
presenter = new MainPresenter(packageModel);
presenter.addView(this);
}
}