2017-09-03 61 views
0

我正在開發應用程序,其中我想使用MVVM模式。目前,來自xml的所有事件都由將它們傳遞到ViewModel旁邊的活動來處理。例如。用戶點擊登錄按鈕,事件由活動處理;現在這個活動調用視圖模型的方法,在這個方法裏面我調用了RxFirebase(Firebase上的Rx包裝),它返回Observable,訂閱它們並返回它;鑑於我再次訂閱這個可觀察的UI做更新。下面介紹了這種情況。在Android中使用RxJava和MVVM模式處理錯誤

我的問題是如果這種方法是正確的?在我看來,更好的解決方案是處理ViewModel中的錯誤,但我怎麼才能更新UI?其中一個解決方案是創建界面,例如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(); 
      } 
     }); 
} 

視圖模型方法:

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

你的答案是,除了幾乎正確的,你應該單獨查看和(業務)編輯邏輯。如果您在使用架構組件時使用的數據綁定是,強烈建議,這將是您的嘗試。

這意味着更新UI的所有內容應該位於View中,與視圖無關的所有內容都應位於ViewModel中。

這意味着你可以將你的ViewModel傳遞給你的Layout,它有一個onClick並且調用ViewModel中的Method。例如:

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

現在,您可以處理的onClick您的視圖模型內像

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

如果「真的」要觀察從您的視圖錯誤,你既可以創建一個ObservableBoolean被設置爲True onec出現錯誤並訂閱更改。你可以把它視圖模型裏面,如:

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

現在你可以觀察布爾您查看

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

內如果你不使用數據綁定,它幾乎只是你傳遞一個ClickListener相同的按鈕。

表示您在View中偵聽OnClick,在您的ViewModel中調用「處理」方法,並在發生錯誤時更新ObservableBoolean。由於您傾聽了更改,您可以在視圖內處理SnackBar內容。

Snackbar和涉及視圖的所有內容都應該與ViewModel分開,除了導航器。在這種情況下,您應該創建WeakReferences以避免泄漏。

注意ObservableBoolean是不是 RxJava的一部分。它是架構組件的一部分。

如果你想解決它使用RxJava,你可以在你的視圖模型像創建PublishSubject:

Viewmodel.java

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

最後,在您的視圖觀察它

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

請注意,您將您的RxJava訂閱置於您的ViewModel界面中的onCleared()

編輯:我還沒有測試代碼,因爲我目前只有Kotlin項目,但應該在java中工作。

在您的代碼中發現了一個問題,如果mBinding爲null,您沒有驗證。這可能是空的,因爲您訂閱了更改並嘗試在視圖中創建SnackBar,該視圖可能已被處置。始終使用if (mBinding != null) Snackbar.snackysnacky(..)

+0

我正在使用數據綁定。我在View中處理事件的原因是我想讓ViewModel平臺獨立。我已經閱讀了兩種方法 - 第一種解決方案由我使用 - 處理程序接口由活動實現並由xml使用,第二種方法是您的方法視圖參數應該被忽略並且從不使用。 無論如何 - 感謝您的回答,我將在我的應用程序中使用Architecture Components Observable字段! – rubin94

+0

因爲它不是真正的mvvm,所以您可以將處理程序放入您的ViewModel中並在您的佈局中調用它們(因爲這可以在沒有視圖的情況下進行測試和調用),也可以將視圖傳遞給您的佈局,並在您的視圖。 –

+0

我還有一個問題 - 是否有任何理由使用PublishSubject或Architecture Component的Observable? 我知道架構組件處於alpha階段,所以目前RxJava似乎是更好的解決方案? – rubin94