2017-10-21 61 views
0

Bonjour J'essaie d'utiliser la liaison de données et l'architecture mvvm dans mon application Android. Je veux ajouter l'écouteur de clic utilisant la liaison de données dans la disposition et envoyer les valeurs de nom d'utilisateur et mot de passe edittext au modèle de vue et exécutera le service Web et appellera la méthode appropriée de LoginActivity comme startHomeActivity().Comment définir l'écouteur de clic et transmettre la valeur des champs edittext pour afficher le modèle à l'aide de la liaison de données

Est-ce que quelqu'un sait comment faire cela ou est-ce que je prends une mauvaise approche? J'ai extrait de code ci-dessous de mon activité, modèle mise en page et vue

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> 

Répondre

2

d'abord tous renommer votre ViewModel. Son séparé par la vue qui signifie que le nom devrait être quelque chose comme LoginViewModel. Pour cette tentative (qui est le meilleur disponible en utilisant le modèle mvvm dans Android), vous avez besoin de AAC/LiveData. Deuxièmement, vous devez effectuer une liaison de données bidirectionnelle et affecter le ViewModel à votre mise en page.

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

Cela nécessite une ObservableField<String> dans votre ViewModel.

Maintenant, vous voulez valider si un clic s'est produit en transmettant l'événement Click dans votre activité. Dans ce cas, vous créez l'écouteur dans votre ViewModel et transmettez les données à un observable.

class LoginViewModel { 

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

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

Après cela, vous pouvez utiliser votre activité ou Fragment d'observer pour UIEvents en utilisant LiveData (qui est sensible au cycle de vie!).

Maintenant, vous pouvez utiliser tout fragment/activité qui est liée à la ViewModel d'observer pour les événements de l'interface utilisateur comme:

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

Vous avez besoin de la classe SingleLiveData qui est un MutableLiveData mais annulerait vos données ONEC son émis.

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

Il y a plusieurs tentatives de faire ça avec WeakReferences pour éviter la fuite de contexte, mais je recommande fortement de faire pas. La raison est que vous voulez diviser la logique avec votre vue. Avoir des références même si elles sont paresseuses ou faibles brise l'architecture.

+0

Merci beaucoup +1 :) –