2017-10-21 12 views
0

こんにちは私は、アンドロイドアプリでデータバインディングとmvvmアーキテクチャを使用しようとしています。レイアウト内のデータバインディングを使用してクリックリスナを追加し、ユーザ名とパスワードの値をビューモデルに送信して、Webサービスを実行し、startHomeActivity()のような適切なメソッドLoginActivityを呼び出します。クリックリスナーを設定し、edittextフィールドの値をデータバインディングを使用してモデルを表示する方法

誰でもこれを行う方法を知っていますか、間違ったアプローチをしていますか?私は私の活動、レイアウトとビューモデルのコードのスニペット

LoginActivity.ktの下に持って

class LoginActivity : BaseActivity(), LoginNavigator { 

    @Inject 
    lateinit var loginViewModel: LoginActivityViewModel 

    override fun onCreate(savedInstanceState: Bundle?) { 
     super.onCreate(savedInstanceState) 

     val activityLoginBinding = DataBindingUtil.setContentView<ActivityLoginBinding>(this, R.layout.activity_login) 


    } 

    override fun startHomeActivity() { 
     TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 
    } 

    override fun startRegistrationActivity() { 
     TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 
    } 

    override fun startForgotPasswordActivity() { 
     TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 
    } 

    override fun handleError(throwable: Throwable) { 
     TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 
    } 

} 

LoginActivityViewModel.kt

class LoginActivityViewModel { 


    fun login(email: String, password: String) { 

    } 

    /** 
    * Validate email and password. It checks email and password is empty or not 
    * and validate email address is correct or not 
    * @param email email address for login 
    * @param password password for login 
    * @return true if email and password pass all conditions else false 
    */ 
    fun isEmailAndPasswordValid(email: String, password: String): Boolean { 

     if (email.isEmpty()) return false 

     if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) return false 

     if (password.isEmpty()) return false 

     return true 
    } 

} 

activity_login.xmlの

<layout> 

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto" 
     xmlns:tools="http://schemas.android.com/tools" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:fillViewport="true" 
     tools:context="com.app.android.login.LoginActivity" 
     tools:ignore="missingPrefix"> 

     <android.support.constraint.ConstraintLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:paddingBottom="@dimen/default_view_margin_bottom_8dp"> 

      <android.support.design.widget.TextInputLayout 
       android:id="@+id/til_login_email" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginEnd="@dimen/default_view_margin_right_8dp" 
       android:layout_marginStart="@dimen/default_view_margin_left_8dp" 
       android:textColorHint="@color/colorSecondaryText" 
       app:hintTextAppearance="@style/AppTheme.InputLayoutStyle" 
       app:layout_constraintBottom_toTopOf="@+id/til_login_password" 
       app:layout_constraintTop_toTopOf="parent" 
       app:layout_constraintVertical_chainStyle="packed"> 

       <android.support.design.widget.TextInputEditText 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:hint="@string/login_email" 
        android:imeOptions="actionNext" 
        android:singleLine="true" 
        android:textColor="@color/colorPrimaryText" /> 
      </android.support.design.widget.TextInputLayout> 

      <android.support.design.widget.TextInputLayout 
       android:id="@+id/til_login_password" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginEnd="@dimen/default_view_margin_right_8dp" 
       android:layout_marginStart="@dimen/default_view_margin_left_8dp" 
       android:textColorHint="@color/colorSecondaryText" 
       app:hintTextAppearance="@style/AppTheme.InputLayoutStyle" 
       app:layout_constraintBottom_toTopOf="@+id/btn_login_login" 
       app:layout_constraintTop_toBottomOf="@+id/til_login_email" 
       app:layout_constraintVertical_chainStyle="packed"> 

       <android.support.design.widget.TextInputEditText 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:hint="@string/login_password" 
        android:imeOptions="actionDone" 
        android:singleLine="true" 
        android:textColor="@color/colorPrimaryText" /> 
      </android.support.design.widget.TextInputLayout> 

      <Button 
       android:id="@+id/btn_login_login" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginEnd="@dimen/default_view_margin_right_8dp" 
       android:layout_marginStart="@dimen/default_view_margin_left_8dp" 
       android:layout_marginTop="48dp" 
       android:text="@string/login_btn_text" 
       android:textColor="@color/colorWhite" 
       app:layout_constraintBottom_toTopOf="@+id/textview_login_forgot_password" 
       app:layout_constraintTop_toBottomOf="@+id/til_login_password" 
       app:layout_constraintVertical_chainStyle="packed" /> 

      <TextView 
       android:id="@+id/textview_login_forgot_password" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginEnd="@dimen/default_view_margin_right_8dp" 
       android:layout_marginStart="@dimen/default_view_margin_left_8dp" 
       android:layout_marginTop="36dp" 
       android:gravity="center" 
       android:text="@string/login_forgot_password" 
       app:layout_constraintBottom_toTopOf="@+id/btn_login_register" 
       app:layout_constraintTop_toBottomOf="@+id/btn_login_login" 
       app:layout_constraintVertical_chainStyle="packed" /> 

      <Button 
       android:id="@+id/btn_login_register" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginEnd="@dimen/default_view_margin_right_8dp" 
       android:layout_marginStart="@dimen/default_view_margin_left_8dp" 
       android:text="@string/login_sign_up" 
       android:textColor="@color/colorWhite" 
       app:layout_constraintBottom_toBottomOf="parent" /> 

     </android.support.constraint.ConstraintLayout> 
    </ScrollView> 
</layout> 

答えて

2

ファーストすべてあなたのViewModelの名前を変更します。 Viewによって分離されています。これは、名前がLoginViewModelのようなものでなければならないことを意味します。この試み(これは、アンドロイドでmvvmパターンを使用すると最も有効です)には、AAC/LiveDataが必要です。

第2に、双方向データバインディングを行い、ViewModelをレイアウトに割り当てる必要があります。あなたのViewModelでObservableField<String>を必要

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto"> 
<data> 
    <variable name="viewModel" type="...YourVm" /> 
</data> 
<android.support.design.widget.TextInputEditText ... 
        android:text="@={viewModel.yourField}" /> 

<Button ... onClick="@{viewModel.onClick}" /> 
</layout> 

クリックイベントがアクティビティに渡されることでクリックが発生したかどうかを検証します。その場合、ViewModelでリスナーを作成し、そのデータをObservableに渡します。

class LoginViewModel { 

    val yourField = ObservableField<String>() 
    val uiEventLiveData = SingleLiveData<Int>() 

    fun onClick(view:View) { 
     uiObservable.data = 1 // or any other event 
    } 
} 

この後、LiveData(ライフサイクル対応です)を使用して、アクティビティまたはフラグメントを使用してUIEventを観察できます。

は今、あなたのようなUIのイベントのために観察するためのViewModelにバインドされている任意のフラグメント/アクティビティを使用することができます。

class YourActivity { 


private val yourvm by lazy { ViewModelProviders.of(this, viewModelFactory).get(Yourvm::class.java) } 

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { 
    // .... 
    binding.viewModel = yourVm 
} 

override fun onActivityCreated(savedInstanceState: Bundle?) { 
    super.onActivityCreated(savedInstanceState) 

    yourVm.uiEventLiveData.observe(this, Observer { 
      when(it) { 
      1-> { doSomeLoginStuff(yourVm.yourField, ...) } //click happened, do something 
      else -> .... // unknown ui event 
      } 
    }) 
} 

あなたはMutableLiveDataあるクラスSingleLiveDataを必要とするが、その放出されたonecあなたのデータを無効化。

class SingleLiveData<T> : MutableLiveData<T>() { 

    private val mPending = AtomicBoolean(false) 

    @MainThread 
    override fun observe(owner: LifecycleOwner, observer: Observer<T>) { 

     if (hasActiveObservers()) { 
      Log.w(TAG, "Multiple observers registered but only one will be notified of changes.") 
     } 

     // Observe the internal MutableLiveData 
     super.observe(owner, Observer { t -> 
      if (mPending.compareAndSet(true, false)) { 
       observer.onChanged(t) 
      } 
     }) 
    } 

    @MainThread 
    override fun setValue(t: T?) { 
     mPending.set(true) 
     super.setValue(t) 
    } 

    /** 
    * Used for cases where T is Void, to make calls cleaner. 
    */ 
    @MainThread 
    fun call() { 
     value = null 
    } 

    companion object { 
     private val TAG = "SingleLiveData" 
    } 
} 

は、コンテキスト漏れを避けるためにWeakReferencesでそれを行ういくつかの試みがありますが、私は非常にそれをやってないことをお勧めします。理由は、あなたの視点と論理を分割したいということです。怠け者でも脆弱であっても、参照を持つことでアーキテクチャが壊れます。

+0

ありがとうございました+1 –

関連する問題