2017-09-03 8 views
0

MVVMパターンを使用したいアプリケーションを開発中です。現在、xmlのすべてのイベントは、ViewModelの横にそれらを渡すアクティビティによって処理されます。例えば。ユーザがログインボタンをクリックすると、イベントはアクティビティによって処理されます。このメソッドの中で、Observableを返すRxFirebase(FirebaseのRxラッパー)メソッドを呼び出し、それらにサブスクライブして返します。私は再びUIの更新を行うためにこの観察可能なものを購読しています。この状況を以下に示します。AndroidでのRxJavaとMVVMパターンによるエラー処理

私の質問は、このアプローチが正しいかどうかです。私の意見では、よりよい解決策はViewModelのエラーを処理することですが、どうすればUIを更新できますか?ソリューションの1つは、インターフェースを作成することです。 ShowMessageListener、次にViewModelに渡してメッセージを表示しますが、これにRxJavaを使用することをお勧めします。

表示方法:

public void onLoginClick(View view) { 
    mBinding.clProgress.setVisibility(View.VISIBLE); 
    mViewModel.onLoginClick().subscribe(authResult -> { 
      mBinding.clProgress.setVisibility(View.GONE); 
      startAnotherActivity(); 
     }, throwable -> { 
      mBinding.clProgress.setVisibility(View.GONE); 
      if (throwable instanceof FirebaseApiNotAvailableException) { 
       Snackbar.make(mBinding.getRoot(), R.string.google_play_services_unavilable, Snackbar.LENGTH_LONG).show(); 
      } else { 
       Snackbar.make(mBinding.getRoot(), throwable.getMessage(), Snackbar.LENGTH_LONG).show(); 
      } 
     }); 
} 

のViewModel方法:

public Observable<AuthResult> onLoginClick() { 
    Observable<AuthResult> observable = RxFirebaseAuth.signInWithEmailAndPassword(mAuth, mEmail.get(), mPassword.get()); 
    observable.subscribe(authResult -> { 
     //save user 
    }, throwable -> { 
     //handle error 
    }); 
    return observable; 
} 
+0

答えがあなたのニーズに合っていればいいと思いますが、コメントではなく、この場合はサンプルを伸ばしてください。 –

答えて

0

あなたの答えはあなたが本当に別々のビューと(ビジネス)-Logic必要があることを除いて、ほぼ正しいです。これは、というデータバインディングを使用する場合、アーキテクチャコンポーネントを使用する場合はを強くお勧めします。

つまり、UIを更新するものはすべてあなたのビューになければなりません。ビューに関係のないものはViewModelになければなりません。

つまり、ViewModelをレイアウトに渡すことができます。レイアウトにはonClickがあり、ViewModelでメソッドを呼び出します。例:

<?xml version="1.0" encoding="utf-8"?> 
<layout ..> 
    <data><variable name="viewModel" type="YourVm" /></data> 
    <Button onClick="@{viewModel::onButtonClick} 
</layout> 

今、あなたはあなたが「本当に」あなたのビューからエラーを観察したい場合は、Trueに設定されているObservableBooleanを作成することができますいずれか

public void onClick(View view) { 
Log.d("Click", "My Button was clicked"); 
} 

のようなあなたのViewModel内のonClickを扱うことができますonecにエラーがあり、変更を購読しています。あなたはあなたにClickListenerを渡すことを除いて、それはほぼ同じだデータバインディングを使用しない場合は今、あなたはあなたのビュー内

yourViewModel.obserableError.observe(this, result -> { 
    // do your error stuff 
}); 

をブールを観察することができ

public final ObservableBoolean observableError = new ObservableBoolean(); 
public void onClick(...) { observableError.set(true); } 

:あなたは次のようにViewModelに内側に置くことができますボタン。

ViewでOnClickをリッスンし、ViewModelで "processing"メソッドを呼び出し、エラーが発生した場合にObservableBooleanを更新することを意味します。変更を聞いているので、あなたのビューの中でSnackBarのものを処理することができます。

スナックバーとビューを含むすべてのものは、ナビゲータを除いてViewModelから実際に分離する必要があります。この場合、WeakReferenceを作成してリークを避ける必要があります。

ObservableBooleanがで、RxJavaのでないことに注意してください。これはArchitecture Componentsの一部です。

あなたがRxJavaを使用してそれを解決したい場合は以下のようにあなたのViewModelにPublishSubjectを作成することができます。

Viewmodel.java

public final PublishSubject<String> ps = PublishSubject.create<>() 
public void onClick(...) { ps.next("my evil error string"); } 

そして最後には、あなたのビューで

myViewModel.ps.subscribe(data -> {...}, error -> { ... }) 

それを守ってあなたのViewModelインターフェイスにあるonCleared()にあなたのRxJavaサブスクリプションを配してください。

編集:私はコードをテストしていません。私は現在、Kotlin Projectsしか持っていませんが、javaで動作するはずです。

あなたのコードで、mBindingがnullの場合に検証しなかった問題が見つかりました。これは、変更をサブスクライブし、ビューにSnackBarを作成しようとしているため、すでに破棄されている可能性があるため、nullになることがあります。常に使用してくださいif (mBinding != null) Snackbar.snackysnacky(..)

+0

私は今データバインディングを使用しています。 Viewでイベントを処理する理由は、ViewModelプラットフォームを独立させたいからです。私は2つのアプローチについて読んできました。最初の解決策は、私のハンドラインターフェイスがアクティビティによって実装され、xmlによって使用され、2つ目はメソッドビューパラメータを無視して使用しないことです。 答えていただきありがとうございます。私は、アプリケーションでArchitecture Components Observableフィールドを使用しています! – rubin94

+0

アンドロイドでは実際にmvvmではないので、ハンドラをViewModelに配置してレイアウト内で呼び出すことができます(これはテストなしでもビューで呼び出すことができます)。レイアウトにビューを渡してハンドラを作成することもできますビュー。 –

+0

もう1つの質問があります - PublishSubjectまたはArchitecture Component Observablesを使用する理由はありますか? アーキテクチャコンポーネントがアルファステージにあることは知っているので、現在のところRxJavaはより良いソリューションと思われますか? – rubin94

関連する問題