Android MVP中的模型需要上下文

Android MVP中的模型需要上下文,android,mvp,Android,Mvp,在android中使用MVP时,我需要使用模型中的活动上下文来获取所有已安装应用程序的列表。在遵循MVP模式的同时,访问上下文的正确方法是什么,或者其他实现相同目的的方法是什么 以下是课程: Main Activity.java Main Presenter.java 公共类MainPresenter扩展了BasePresenter{ MainModel model; public void onSendButtonClick() { model.getListO

在android中使用MVP时,我需要使用模型中的活动上下文来获取所有已安装应用程序的列表。在遵循MVP模式的同时,访问上下文的正确方法是什么,或者其他实现相同目的的方法是什么

以下是课程:

Main Activity.java Main Presenter.java 公共类MainPresenter扩展了BasePresenter{
    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);
    }
}