2017-10-21 64 views
0

嗨我想在我的android应用程序中使用数据绑定和mvvm体系结构。我想在布局中添加使用数据绑定的点击监听器,并将用户名和密码edittext的值发送到视图模型,并执行web服务并调用LoginActivity的适当方法,如startHomeActivity()如何设置单击侦听器并传递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一样。对于这种尝试(这是在Android中使用mvvm模式的最佳选择),您需要AAC/LiveData

其次,您应该执行双向数据绑定并将ViewModel分配给您的布局。

<?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 ObservableField<String>

现在您想验证在活动中传递点击事件是否发生了点击。对于这种情况,您可以在ViewModel中创建Listener并将数据传递给Observable。

class LoginViewModel { 

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

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

之后,您可以使用您的Activity或Fragment来观察使用LiveData的UIEvents(它是生命周期感知!)。

现在你可以用它绑定到视图模型的任何片段/活动观察像UI事件:

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 
      } 
    }) 
} 

您需要的类SingleLiveData这是一个MutableLiveData而抵消你的数据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 :) –

相关问题