web-dev-qa-db-ja.com

MVPのモデルにコンテキストが必要

Androidでインストールされているすべてのアプリケーションのリストを取得するには、モデルのコンテキストのアクティビティのコンテキストを使用する必要があります。コンテキストにアクセスするための正しい方法や、 MVPパターンに従っても同じです。

ここにクラスがあります:

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

}

パブリッククラスMainPresenterは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);

}

}

getPackageManager()。queryIntentActivities(mainIntent、0)に問題があります。ここにコンテキストがないため、これを行う方法。

12
Harish Sharma

私も同様の質問に回答しました ここ あなたも見てみたいかもしれません。私はあなたがこの特定の問題をどのように解決できると思うかについての内訳を与えます。

Applicationクラスの静的コンテキストを使用します

この方法は機能しますが、私はそれが好きではありません。テストが難しくなり、コードが結合されます。

public class App extends Application {

    private static Context context;

    public static Context getContext() {
        return context;
    }

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

次に、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;
    }
}

これで解決できたので、より良いオプションをいくつか見てみましょう。

アクティビティで実行します

したがって、アクティビティはビューを実装します。おそらく、onActivityResultなど、いくつかのAnrdoidyの処理も行っています。アクティビティにAndroidコードを保持し、Viewインターフェースからアクセスするだけの理由があります。

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

別のクラスで詳細を抽象化します

最後のオプションはMVPのルールに違反しませんが、パッケージのリストを取得するのはreally View操作ではないため、完全に正しくはありません。私が好むオプションは、インターフェース/クラスの背後でコンテキストの使用を隠すことです。

クラスPackageModel(または好きな名前を付けてください)を作成します。

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

これで、コンテキストの使用はプレゼンターから隠され、Androidの知識がなくても続行できます。これはコンストラクタインジェクションと呼ばれます。依存関係注入フレームワークを使用している場合は、すべての依存関係を構築できます。

PackageModelのインターフェイスを作成することもできますが、Mockitoのようなモックフレームワークがインターフェイスを使用せずにスタブを作成できるため、本当に必要だとは思いません。

23
Jahnold