web-dev-qa-db-ja.com

MVVMのコンテキストandroid

AndroidアプリケーションのMVVMアーキテクチャの作業を開始しました。コンテキストをビューモデルに渡すのが正しいかどうか疑問がありますか?そうでない場合、ビューモデルは必要に応じてコンテキストにどのようにアクセスできますか? 。

私は次のことをしています。

  1. EditTextを使用してデータをフィードします。
  2. このデータをビューモデルに送信します。
  3. ビューモデルはこのデータをリポジトリに送信します
  4. このデータをデバイスの共有設定に保存するリポジトリ。

共有設定として、オブジェクトをインスタンス化するためにコンテキストが必要でした。

私はこのアーキテクチャに不慣れです。事前に感謝します。

11
Lalit Kushwah

ApplicationContextの使用は問題ないと思います。AndroidViewModelからViewModelを拡張でき、コンテキストへの参照が必要な場合はいつでもgetApplication()メソッドを使用できます。

さらに良いことに、ダガーを使用している場合、これはまったく必要ありません。必要な場所にApplicationContextを挿入するだけです。ビューモデルや、共有設定などを処理するユーティリティクラスに含めることができます。

7

2019年更新

私は古い投稿でだれにも誤解を与えたくないので、更新した方がいいと思いました。

アーキテクチャコンポーネントとJetPackの最新リリースにより、MVVMは、非常にクリーンな方法でコードベースを分解する実際の適切な構造の真の競争相手になりました。

ビューはアクティビティまたはフラグメントであり、基本的にはxmlが膨らんでいます(これは少し奇妙なMVVMですが、知ってみましょう)。

ViewModelは、ライフサイクルスコープとオブザーバーで現在提供されている実際のViewModelクラスです。これらの新機能とライフサイクル管理ツールにより、ViewModelは、適切なLiveData、Observable Data、または単なる標準モデルを取得するために、Room DBのリポジトリレイヤーまたはRetro APIにアクセスしながらビューのデータを維持するのに非常に適しています。

これは、以前のアーキテクチャ実装日の間、非常に関連があったと思うので、ここに残しますが、アーキテクチャコンポーネントとJetPackを使用していない場合、Boyは見逃しています。コードは非常にすっきりと小さくなっています。 :)

古い返信

これは、Androidコミュニティの間での長い議論です。MVCを参照すると、Model(別名データ保持オブジェクト)がM、Controllers = Cがアクティビティクラスであることは明らかです(iOSの場合)彼らは実際にそれらをUIViewControllersと呼びます)AndroidのビューのVはXMLファイル自体です。ここで、何が何を表すのかについてのアーキテクチャの内訳を主張します。しかし、これを越えてMVVMについて説明しましょう。

MVVMは何年も前から存在しています。これまでに、サードパーティのバインディングツールを介してAndroid=)に変換しようとする試みがいくつかありましたが、結局、よりハッキングされて価値があります。

最近のネイティブデータバインディングのリリースでAndroidがついにMVVMのややクリーンな実装を行うことができるようになりました。そのため、ここにいくつかのオプションがあります。

M =モデル(データ保持オブジェクト)

V =ビュー(UIを表すXMLファイル自体)

VM =ここで議論が起こります。

「真の」ViewModelになるためには、プレゼンテーション層からの真の分離が必要であり、Activityクラス自体にライフサイクルコールバックがあるため、ViewModelと呼ばれる価値がないと言う人もいます。

他の人は、ViewModelからトリガーされるアクションのほとんどを処理するために、onActivityResult、onNewIntent、onBroadcastReceived、onPause、またはユーザーエクスペリエンスを適切に管理するための他のライフサイクル処理を認識する必要があると指摘します。私のチームでは、アクティビティをViewModelと見なしています。それ以外の場合は、アクティビティをビューモデルに渡し、いずれにしても2つを密に結合して、コードの巨大な恐ろしいメンテナンスの悪夢を作ります。

したがって、私の意見が必要な場合は、アクティビティをViewModelとして扱うことに固執してください。 WPFのINotifyPropertyChangedなどの他のバインディングテクノロジーと同じように、データをViewModelに取得します。あなたはBindingを通してそれを行います。

これを実現するために2つのことを行います。 1つは、XMLレイアウトにActivity変数があり、バインディング設定のonCreateに挿入することで、viewModelまたはアクティビティの監視可能なプロパティへのXML直接バインディング権限を付与します。次に、使用する必要のある変数を注入します。たとえば、onCreateでも設定するActivity内にあるWeatherModelにデータを入力して、XMLがViewModel(別名アクティビティ)にアクセスできるようにします。そしてそれはviewModelのオブジェクトです。

もう1つの方法は、ViewModelオブジェクトを作成し、それをアクティビティのonCreateのXMLに挿入してから、アクションとライフサイクルを処理するためにアクティビティからビューモデルへのコールバックを継続して行い、悪夢のハハを気軽に管理することです。この方法でプロジェクト全体を行い、その終わりまでに、私はコーディングの労力と恐ろしい前後のすべての重複を避けるためにすべてをやり直しました。

グッドラックと私はそれが役立つことを願っています。

5
Sam

非常に良い質問です。見た目ほど簡単ではありません。 ここにGoogleチームの例を示します

彼らは工場の助けを借りて問題を解決しました。 (もちろん)アプリケーションコンテキストが渡されます(アクティビティコンテキストではありません!)。

小さな問題-そして多くの定型コード!

私の決定:

public class MainApplication extends Application {
public void onCreate() {
AppSharedPref sharedPref = AppSharedPref.getInstance(PreferenceManager.getDefaultSharedPreferences(this));
AppRepository.getInstance(sharedPref);

リポジトリはシングルトーンです(簡潔にするために、多くのコードは省略されています)。

public class AppRepository implements AppDataSource {
public static AppRepository getInstance(@NonNull AppSharedPref sharedPref) {
if (INSTANCE == null) {
   INSTANCE = new AppRepository(sharedPref);
}
return INSTANCE;
}

ViewModel呼び出し:

public class MyViewModel extends AndroidViewModel {

// constructor
public MyViewModel(@NonNull Application application) {
   repository = AppRepository.getInstance(.....);
}
3
tim4dev

ダガー2を見てください!

それは本当です、ActivityxmlまたはViewModelに絶対に渡すべきではありません。これにより、ViewModelは、このアーキテクチャーから離れようとしているこれらの2000行のアクティビティと同じになります。 MVVMプロジェクトでの解決策は、SharedPreferencesDaggerを注入することです。 ApplicationContextも使用できますが、プロジェクトにSharedPreferencesの複数のインスタンスが必要ですか?

SharedPreferencesのユーティリティクラスがあります。シングルトンにして、必要な場所に注入するのは素晴らしいことです。

0
Rainmaker

この場合は、AndroidViewModelクラスを使用するか、アプリケーションのコンテキストへの参照をViewModel実装で保持する必要があります。 ViewModelクラスは、ライフサークルを通じてActivityの異なるインスタンス間でデータを永続的に保持するように設計されており、Activityインスタンスコンテキストの1つへの参照を保存しても意味がありません。

0
Nikolay

アプリケーションでMVVMを使用しています。私は常にビューモデル内でコンテキストを使用しないようにしています。また、設定ファイルにアクセスするためのコンテキストを必要とするSharedPreferencesの問題も発生しました。 Daggerを使用しない私のソリューションの1つは、アプリケーションコンテキストを参照するPreferenceユーティリティクラスを作成することです。このユーティリティクラスは、Applicationクラスで初期化します。ユーティリティクラスによって提供されるpublic staticメソッドを介して共有設定への参照を取得します。リポジトリクラスからユーティリティクラスを直接呼び出すことができます。私はリポジトリクラスにデータストレージに関連するすべてのロジックを含めることを好みます。そのため、リポジトリクラスでsharedpreferenceユーティリティクラスを呼び出します。

PreferenceManager.Java

public class PreferenceManager {
private static SharedPreferences mSharedpreferences;
private PreferenceManager() {}
public static void initialize(Context context) {
    mSharedpreferences= context.getSharedPreferences(context.getPackageName(), 
    Context.MODE_PRIVATE);
}
public static SharedPreferences getSharedPreferences() {
    return mSharedpreferences;
}
}

App.Java

public class App extends Application {
@Override
public void onCreate() {
    PreferenceManager.initialize(this);
}
}

Repository.Java

public class Repository {
public void someMethod() {
    PreferenceManager.getSharedPreferences.edit.putBoolean("sample", true).apply();
}
0
Gelo