web-dev-qa-db-fra.com

Besoin de contexte dans le modèle dans MVP

J'ai besoin d'utiliser le contexte d'activité dans le modèle lors de l'utilisation de MVP dans Android pour obtenir la liste de toutes les applications installées. Quelle est la bonne façon d'accéder au contexte ou à toute alternative pour atteindre le même en suivant le modèle MVP.

voici les cours:

public class MainActivity extends BaseActivity
    implements MainView,View.OnClickListener {

private MainPresenter mPresenter;



private Button sendButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    init();
    createPresenter();


}

private void init(){

    sendButton= (Button) findViewById(R.id.button_send);
    sendButton.setOnClickListener(this);
}

private void createPresenter() {
    mPresenter=new MainPresenter();
    mPresenter.addView(this);
}





@Override
public void onClick(View view) {
    switch (view.getId()){
        case R.id.button_send:
            mPresenter.onSendButtonClick();
            break;
    }
}

@Override
public void openOptionsActivity() {
    Intent intent=new Intent(this,OptionsActivity.class);
    startActivity(intent);
}

}

public class MainPresenter étend BasePresenter {

MainModel model;
public void onSendButtonClick(){

   model.getListOfAllApps();

}

@Override
public void addView(MainView view) {
    super.addView(view);
model=new MainModel();
}

}

public class MainModel {

public void getListOfAllApps(){
    final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
    mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    final List pkgAppsList = getPackageManager().queryIntentActivities(mainIntent, 0);

}

}

avoir un problème dans getPackageManager (). queryIntentActivities (mainIntent, 0). comment le faire sans avoir de contexte ici.

12
Harish Sharma

J'ai répondu à une question similaire ici que vous voudrez peut-être également consulter. Je vais cependant vous expliquer comment je pense que vous pourriez résoudre ce problème particulier.

Utilisez un contexte statique de la classe Application

Cette méthode fonctionnerait mais je ne l'aime pas. Cela rend les tests plus difficiles et couple votre code ensemble.

public class App extends Application {

    private static Context context;

    public static Context getContext() {
        return context;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }
}

Puis dans votre 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;
    }
}

Maintenant que nous avons ce problème, examinons de meilleures options.

Faites-le dans l'activité

Votre activité implémente donc votre vue. Il fait probablement aussi quelques choses d'Anrdoidy comme onActivityResult. Il y a un argument pour garder Android code dans l'activité et simplement y accéder via l'interface View:

public interface MainView {

    List<String> getListOfAllApps();
}

L'activité:

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;
    }

    //..
}

Et le présentateur:

public class MainPresenter extends BasePresenter {

    public void onSendButtonClick(){

        view.getListOfAllApps();
    }
}

Résumé des détails dans une classe séparée

Bien que la dernière option ne viole pas les règles de MVP, elle ne semble pas tout à fait correcte car obtenir une liste de packages n'est pas vraiment une opération View. Mon option préférée est de masquer l'utilisation du contexte derrière une interface/classe.

Créez une classe PackageModel (ou quel que soit le nom qui vous plaît):

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;
    }
} 

Demandez maintenant à votre présentateur d'exiger cela comme paramètre constructeur:

public class MainPresenter extends BasePresenter {

    private PackageModel packageModel;

    public MainPresenter(PackageModel packageModel) {
        this.packageModel = packageModel;
    }

    public void onSendButtonClick(){

        packageModel.getListOfAllApps();
    }
}

Enfin dans votre activité:

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);
    }
}

Maintenant, l'utilisation du contexte est cachée au présentateur et il peut se poursuivre sans aucune connaissance d'Android. Ceci est connu sous le nom d'injection de constructeur. Si vous utilisez un framework d'injection de dépendances, il peut créer toutes les dépendances pour vous.

Si vous le souhaitez, vous pouvez créer une interface pour PackageModel, mais je ne pense pas que ce soit vraiment nécessaire, car un cadre de simulation comme Mockito peut créer un stub sans utiliser d'interface.

23
Jahnold