2016-08-23 3 views
5

AndroidのMVPを使用して、インストールされているすべてのアプリケーションのリストを取得する際に、モデルのアクティビティのコンテキストを使用する必要があります。 MVPパターンに従うときも同じです。ここで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)。ここにコンテキストがないとしてください。

1)は常にモデルからContextを渡す:

+1

'アプリケーションクラス'はありませんか? –

+0

私はアプリケーションclass.butを使用する方法を知っています。アプリケーションクラスで使用するためにコンテキストにいくつかの定数フィールドを使用すると言っていますか?問題はモデルごとにアンドロイド固有のクラス/オブジェクトを使用しないでください。 –

+0

全くありません。 onCreate(...)でapplicationContextを作成して使用します。 –

答えて

14

私も同様の質問hereにお答えしましたが、あなたも見てみたいです。私はあなたがこの特定の問題を解決できると思う方法の内訳を教えてあげます。

Applicationクラス

このメソッドは動作しますが、私はそれが好きじゃないから、静的なコンテキストを使用してください。これはテストをより困難にし、コードを結合させます。次に、あなたのMainModelで

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

は、今、私たちは道をそれを持っている、のは、いくつかのより良いオプションを見てみましょう。

は、だからあなたの活動は、あなたのビューを実装活動

でそれを行います。おそらくonActivityResultのようないくつかの奇形のことをやっているでしょう。ビューインタフェースを介してそれにアクセスするだけの活動でAndroidのコードを維持するとの引数があります:

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のルールを破るものではありませんが、パッケージのリストを取得するのが実際にはのView操作ではないので、まったく気になりません。私の好ましいオプションは、インターフェイス/クラスの背後にContextの使用を隠すことです。

クラス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); 
    } 
} 

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

もしあなたがPackageModelのためのインターフェイスを作ることができたら、私はMockitoのような模擬フレームワークがインターフェイスを使わずにスタブを作ることができるので本当に必要ではないと思います。

+3

[このコメント]として(http:// stackoverflow。#comment61849985_37138822)によると、それは依存性を隠しているだけです。これは悪いことです。同じスレッド上の[回答](http://stackoverflow.com/a/372​​16407/1276636)は非常に良いので、依存関係は非常に明確です。シングルトンや隠された依存関係について[このビデオ](https://www.youtube.com/watch?v=-FRm3VPhseI&index=2&list=PL693EFD059797C21E)が素晴らしいことがわかりました。 – Sufian

+0

私はちょっとポイント3を調整し、PackageModelをインターフェイスにしてgetListOfAllApps()メソッドを1つのメソッドにします。 –

+0

あなたの最初の方法はひどいです。ちょうど最初の方法を削除します。その絶対に間違っている。プレゼンターとモデルは純粋なjavaにする必要があります。 インターフェイスは真の方法です。 –

-1

は基本的には、次のオプションがあります。 Androidで何が起こったとしても、あなたはいつも何らかの種類のContextを持っています。 (そしてあなたのコードはイベントに応答してのみ呼び出されます。)

2)getApplicationContext()静的変数に格納しておいてください。

ActivityContextですが、活動へのリンクを保存する場合は、メモリリークを取得:

は、次の落とし穴があります。たとえば、画面が回転したときにアクティビティが再作成されます。 BroadcastReceiversと他の種類のコンテキストに渡されるコンテキストについても同じです。それらのすべては生涯を持っており、生涯はあなたが必要とするものではありませんモデル

あなたのアプリケーションはAndroidによって強制終了され、再起動される可能性があります。この場合、いくつかのグローバル(静的)変数はnullに設定されます。。つまり、アプリケーションで何か問題が発生しない限り、nullになります。特に、再起動シナリオの1つでは、アプリケーションコンテキストを指す静的変数がnullになることがあります。このような問題は、テストするのが難しいです。

+2

のようなAndroid固有のオブジェクトに直接依存してはいけません。プレゼンターとモデルではコンテキストを使用しないでください。このコードはテスト可能ではありません。 –

関連する問題