質問:データバインディングを使用せずに、MVVMでAndroidアプリを実装できますか?.
私が解決しようとしている問題は非常に単純です。バックエンドAPIからアイテムのリストを読み取り、それらをRecylerviewに表示します。
私がどのように実装しているか:
ビュー内-アクティビティとRecyclerViewAdapterモデルがあります:ApiResponseとデータモデルネットワーク-レトロフィットAPIサービス、RxJava2
viewModel部分の場合-基本的にRetrofitServiceを呼び出し、RxJava呼び出しを使用してデータを取得するViewModelクラス(何からも派生しない)があります。
ViewModelには次のような呼び出しがあります:
void getItems();
void addItemData();
void removeItem();
rXJava2でサービスを呼び出す
ObServable<ApiResponse> getItems();
ObServable<ApiResponse> addItemData();
ObServable<ApiResponse> removeItem();
ビューはViewModelオブジェクトをインスタンス化します。 ViewModelは、作成中にAdapterオブジェクトのインスタンスを取得します。ビューで、ボタンをクリックすると、ViewModel#getItems()メソッドを呼び出すアクティビティのClickHandlerが呼び出されます。 ViewModelにはアダプタへのリンクがあるため、viewModelはアダプタ内のアイテムを更新して、RecyclerViewが自動的に更新されるようにします。
これがMVVMにとって正しいアプローチであるかどうかはわかりません。
データバインディングは、私にはスパゲッティのように思えます。
繰り返しますが、MVVMをAndroidでDataBindingなしで実装できますか?アプローチは大丈夫ですか?
はい!あなたはできる。しかし、私はあなたのアプローチがより良くなることができると思います。ビューモデルにビューへの参照があってはならないことに注意してください。 ViewModelはオブザーバブルを公開します。ビューでは、これらのオブザーバブルを観察し、変更に対応する必要があります。あなたはこのようなものを持つことができます:
注:この例はKotlinとLiveDataを使用しているため、なぜですか?しかし、これを使用してJava&Rxで使用できます。
ItemsViewModel : ViewModel() {
private val items = MutableLiveData<List<Items>>()
fun getAllItems() : LiveData<List<Items>> {
return items
}
//..
}
ItemsActivity : Activity() {
private var itemsAdapter: ItemsAdapter? = null
private var viewModel: ItemsViewModel? = null
override fun onCreate(savedInstance: Bundle) {
// ...
// Create your Adapter
itemsAdapter = ItemsAdapter()
recyclerView.adapter = itemsAdapter
// Create and observe your view model
viewModel = ViewModelProviders.of(this).get(ItemsViewModel::class.Java)
viewModel.getAllItems().observe(this, Observer {
it?.let {
adapter?.datasource = it
}
}
この場合、ビューはビューモデルを監視し、アダプタに通知します。次に、アダプタで、データバインディングを使用せずに、通常どおりバインドを実行します。
間違いなく可能ですが、MVVMの「バインディング」部分をどのように解釈するかは完全にあなた次第です。私たちのチームでは、Androidデータバインディングの代わりにRxJavaでMVVMを使用します。ViewModelには、次のような出力と入力のインターフェイスがあります。
interface TasksViewModel {
// inputs
Observer<Task> taskAddedTrigger();
Observer<Task> taskClickedTrigger();
Observer<Task> taskCompletedTrigger();
// outputs
Observable<Boolean> isLoading();
Observable<List<Task>> tasks();
}
次に、ViewModelはRxJavaを使用して、非常に機能的なスタイルで入力を出力にマップします。 Fragmentは、ユーザー入力を受信するたびにViewModelに入力を提供します。出力をサブスクライブし、ViewModelの出力が変更されると、それに応じてユーザーインターフェイスを更新します。 ここにブログ投稿があります トピックを詳細にカバーしています(免責事項:私はそれを書きました)
MVVMの際立った特徴は、ViewModel
がView
に直接結合されていないことです(実際、ViewModel
を別のレイアウトにバインドできます)。これは、単体テストの容易さにも影響を及ぼします。 Adapter
を参照することで、技術的にはMVCに似ています。データバインディングを使用する必要はありませんが、真のMVVMの場合、必要なデータをプルできるように、ビューに変更を通知するための別のオブザーバーパターンメカニズムが必要になると思います。
あなたの言うことSince ViewModel has a link to Adapter
これが問題です。ViewModelにはビューへの参照がないはずです。アダプターにはビューがあるので、これを行うと、MVVMにまったく従わなくなります。
データバインディングなしでMVVMを使用することはできますが、データの変更についてビューに通知する方法が必要です。LiveData(推奨される方法)、Java Observable、Rx、またはカスタム実装ですらあります。ビューは変更と更新自体について通知を受け取ります。あなたの場合、ビューはアダプターを更新します。
例については、ここで私の答えを参照してください MVVMでアクションは許可されていますか?Android