简体   繁体   English

无法使用数据绑定Android从ViewModel与XML通信

[英]Can not communicate with XML from ViewModel using Data binding Android

I am trying to communicate with viewmodel from xml and vice versa using MVVM pattern. 我正在尝试使用MVVM模式与xml中的viewmodel通信,反之亦然。 I have worked on databinding before and successfully worked with Live Data - Dagger - MVVM . 我之前从事数据绑定工作,并成功使用Live Data-Dagger-MVVM Recently, I have tried to create a new project and since then I cannot track the response with XML and viewmodel. 最近,我尝试创建一个新项目,此后,我无法使用XML和viewmodel跟踪响应。 Neither the onClick from XML -> ViewModel nor the assigning value to the textview from View -> XML is working. XML的onClick- > ViewModel或从View- > XML的textview赋值均无效。 But there is no crash or anything, just it is not working. 但是没有崩溃或任何故障,只是它没有工作。 I have added all associated files [ MainActivity, activity_main, viewModel, Dagger Module, build.gradle ] 我已经添加了所有关联的文件[MainActivity,activity_main,viewModel,Dagger模块,build.gradle]

I will really appreciate if anyone can tell me what is going wrong here. 如果有人能告诉我这里出了什么问题,我将不胜感激。

activity_main.xml activity_main.xml

<?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"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable
        name="viewmodel"
        type="aveek.com.vm.ui.home.MainActivityViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

 <TextView

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{viewmodel.balanceText}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:clickable="true"
        android:onClick="@{() -> viewmodel.clickData()}"
        app:layout_constraintTop_toTopOf="parent" />
...
</layout>

MainActivity.kt MainActivity.kt

class MainActivity : AppCompatActivity(),LifecycleOwner {

@Inject
lateinit var binding : ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    AndroidInjection.inject(this)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    binding.setLifecycleOwner(this) 
    with(binding){
        this.viewmodel?.let {
            it.balanceText.set( "Aveek testing")
            it.data.observe(this@MainActivity, Observer {
                Toast.makeText(this@MainActivity, "Data is now : $it", Toast.LENGTH_SHORT).show()
            })
           }
         }
       }

MainActivityViewModel.kt MainActivityViewModel.kt

class MainActivityViewModel : ViewModel() {
val data = MutableLiveData<Boolean>()
val balanceText = ObservableField<String>()
 fun clickData(){
    data.value = false
 }
}

MainActivityModule.kt MainActivityModule.kt

@Module
class  MainActivityModule{

/**
 * provides binding to  Main Activity from respective XML
 * @property viewModel
 * @property context
 * @return binding of the view
 */
@Provides
fun binding(context: MainActivity, viewModel : MainActivityViewModel) : 
ActivityMainBinding {
    val binding = DataBindingUtil.setContentView<ActivityMainBinding>(context, 
    R.layout.activity_main)
    binding.viewmodel = viewModel
    return binding
 }
}

build.gradle build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt'

android {
   compileSdkVersion 27
   defaultConfig {
    applicationId "aveek.test"
    minSdkVersion 15
    targetSdkVersion 27
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    vectorDrawables.useSupportLibrary = true
   }
   dataBinding {
    enabled = true
   }
   buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 
     'proguard-rules.pro'
    }
    }
    compileOptions {
     sourceCompatibility JavaVersion.VERSION_1_8
     targetCompatibility JavaVersion.VERSION_1_8
    }
   }

kapt {
  generateStubs = true
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:multidex:1.0.2'
implementation 'com.android.support:design:27.1.1'
implementation "android.arch.lifecycle:extensions:1.1.0"
//    annotationProcessor "android.arch.lifecycle:compiler:1.1.0"

kapt "com.android.databinding:compiler:$androidPluginVersion"

annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"


implementation "com.google.dagger:dagger:$daggerVersion"
implementation "com.google.dagger:dagger-android:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso- 
core:3.0.2'

}


ext{
    kotlin_version = '1.2.31'
    androidPluginVersion = '3.1.0'
    daggerVersion = '2.13'
}

您将无法使用任何生成的方法来将变量设置为绑定,因为除了ViewDataBinding之外没有通用的超类,因此您将被迫使用反射,或者可以使用便捷方法setVariable():

binding.setVariable(BR.viewModel, viewModel);

As I suspected, the problem is with Dagger injection. 正如我所怀疑的那样,问题出在Dagger注入。 Maybe I have implemented in a wrong approach but the viewmodel is perfectly fine if running without DI. 也许我用错误的方法实现了,但是如果没有DI的话,viewmodel就可以了。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    viewModel = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.viewmodel = viewModel

    binding.setLifecycleOwner(this)
    mLifecycleRegistry = LifecycleRegistry(this).apply {
        markState(Lifecycle.State.CREATED)
    }
    with(binding){
        this.viewmodel?.let {
            it.balanceText.set( "Aveek testing")
            it.data.observe(this@MainActivity, Observer {
                Toast.makeText(this@MainActivity, "Data is now : $it", 
          Toast.LENGTH_SHORT).show()
            })
        }
    }
}

So, I have gone through the DI code and found out that in MainActivity.onCreate() I was doing this 因此,我遍历了DI代码,发现在MainActivity.onCreate()中我正在执行此操作

AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

which basically overriding the databinding behaviour. 基本上是覆盖了数据绑定行为。 So I have updated the code like this 所以我更新了这样的代码

AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
// and initiated binding here as injecting binding from module before setting content won't be effective
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

And removed 并删除

//    @Inject
//    lateinit var binding : ActivityMainBinding

Now it works perfectly fine.. 现在它可以正常工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从Android项目到ViewModel的数据绑定 - Data Binding from Android project to ViewModel MVVM(数据绑定)中的ViewModel与Android建筑组件中的ViewModel有何不同 - How ViewModel in MVVM (data binding) is differ from ViewModel in Android Architectural components Android数据绑定在自定义视图中注入ViewModel - Android data binding inject ViewModel in custom view android viewmodel mutablelivedata 不更新,2 路数据绑定 - android viewmodel mutablelivedata not updating, 2 way data binding Android:使用数据绑定调用 ViewModel 函数 - Android: Call ViewModel function with Data Binding 结合android ViewModel和数据绑定的最佳实践 - Best practice to combine android ViewModel and data binding Android App 将数据从 ViewModel 传递到 ViewModel - Android App pass data from ViewModel to ViewModel 如何使用 viewmodel 和 livedata 将数据从 recyclerview 传递到 android 中的片段 - How can i pass the data from recyclerview to fragment in android using viewmodel and livedata ANDROID可以在xml数据绑定中声明内置数据类型 - ANDROID Can declare Built-In data type in xml data binding 在使用Android数据绑定时,如何通过xml为自定义setter传递多个参数 - How can I pass multiple arguments via xml for a custom setter when using Android data binding
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM