Ich beantwortete eine ähnliche Frage here, die Sie sich vielleicht auch ansehen möchten. Ich werde die Aufschlüsselung darüber geben, wie ich denke, dass Sie dieses spezielle Problem lösen könnten.
Verwenden Sie einen statischen Kontext aus der Anwendungsklasse
Diese Methode funktionieren würde, aber ich bin nicht gern davon. Es macht Tests schwieriger und koppelt Ihren Code zusammen.
public class App extends Application {
private static Context context;
public static Context getContext() {
return context;
}
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
Dann in Ihrem MainModel:
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;
}
}
Jetzt haben wir, dass sich die Art und Weise aufgestellt, wir uns einige bessere Möglichkeiten suchen.
Tun Sie es in der Aktivität
So Ihre Aktivität Ihre Ansicht implementiert. Wahrscheinlich macht es auch ein paar Anrdoidy-Sachen wie onActivityResult. Es gibt ein Argument für die Aktivität Android Code halten und es nur durch die View-Schnittstelle zugreifen:
public interface MainView {
List<String> getListOfAllApps();
}
Die Aktivität:
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;
}
//..
}
Und der Moderator:
public class MainPresenter extends BasePresenter {
public void onSendButtonClick(){
view.getListOfAllApps();
}
}
Zusammenfassung der Details in einer separaten Klasse
Während die letzte Option nicht die Regeln von MVP bricht, fühlt es sich nicht ganz richtig an, da das Abrufen einer Liste von Paketen nicht wirklich ist eine View-Operation. Meine bevorzugte Option ist, die Verwendung von Kontext hinter einer Schnittstelle/Klasse zu verbergen.
Erstellen Sie eine Klasse PackageModel
(oder was auch immer Name Sie Lust):
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;
}
}
nun Ihre Presenter benötigen diese Parameter als Konstruktor haben:
public class MainPresenter extends BasePresenter {
private PackageModel packageModel;
public MainPresenter(PackageModel packageModel) {
this.packageModel = packageModel;
}
public void onSendButtonClick(){
packageModel.getListOfAllApps();
}
}
schließlich in Ihrer Aktivität:
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);
}
}
Jetzt ist die Verwendung von Kontext vom Presenter und es c verborgen ein Weitermachen ohne Android-Kenntnisse. Dies wird als Konstruktorinjektion bezeichnet. Wenn Sie ein Dependency-Injection-Framework verwenden, kann es alle Abhängigkeiten für Sie erstellen.
Wenn Sie wollten, könnten Sie eine Schnittstelle für PackageModel machen, aber ich denke nicht, dass es wirklich notwendig ist, wie ein Spott Framework wie Mockito einen Stub erstellen kann, ohne eine Schnittstelle zu verwenden.
Haben Sie nicht 'Application class'? –
Ich habe die Anwendung class.but aber wie man es benutzt.Sie sagen, dass Sie ein konstantes Feld für den Kontext verwenden, um in der Anwendungsklasse zu verwenden? Das Problem ist gemäß dem Muster, dass wir keine androidspezifische Klasse/Objekt im Modell verwenden sollten. –
Überhaupt nicht. Erstellen Sie einfach applicationContext in onCreate (...) und verwenden Sie es –