android - 来自 Transformation 的数据绑定(bind) LiveData - Android Kotlin

标签 android kotlin android-architecture-components android-livedata android-viewmodel

我正在学习 kotlin 和 android 架构组件。 我有一个谷歌地图上的 map 切换按钮的简单用例。

我想使用数据绑定(bind)将 map 切换按钮标签绑定(bind)到我的 ViewModel 中的 MutableLiveData 字段。

我通过 Activity 中的 onCreate 方法在 MapViewModel 中设置 mapType val。如果我理解正确,这应该会触发 mapLabel val 由于使用 Transformations.map 而发生变化。

它不工作...为什么?

这是我的版本:

  • Android Studio 3.2 Canary 4
  • kotlin_version = '1.2.21'
  • 支持 = "27.1.0"
  • arch_core = "1.1.0"
  • 数据绑定(bind) = "3.2.0-alpha04"

MapViewModel.kt

class MapViewModel : ViewModel() {

    val mapType: MutableLiveData<MapType> = MutableLiveData()

    val mapLabel: LiveData<String> = Transformations.map(mapType, {
        if (it == MapType.MAP) "SAT" else "MAP"
    })
}

enum class MapType {
    SAT, MAP
}

activity_maps.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="vm"
            type="uk.co.oliverdelange.wcr_android_kt.ui.map.MapViewModel" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MapsActivity">

            <Button
                android:id="@+id/map_toggle"
                style="@style/Wcr_MapToggle"
                android:layout_marginTop="110dp"
                android:layout_marginEnd="12dp"
                android:layout_marginBottom="7dp"
                android:layout_gravity="top|end" 
                android:text="@{vm.mapLabel}" />
        </fragment>    
    </FrameLayout>
</layout>

MapsActivity.kt

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap
    private lateinit var viewModel: MapViewModel
    private lateinit var binding: ActivityMapsBinding

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_maps)
        viewModel = ViewModelProviders.of(this).get(MapViewModel::class.java)
        binding.vm = viewModel

        val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        // I can do it this way, but I don't want to. 
        // viewModel.mapLabel.observe(this, Observer { map_toggle.text = it })

        // Here is where i'm setting the MapType on the ViewModel.
        viewModel.mapType.value = MapType.MAP
    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap
    }
}

我已经使用 MutableLiveData 对象测试了绑定(bind),我在该对象中设置了 Activity 中的字符串,它工作正常。问题似乎出在 Transformations.map 上——我是不是理解错了?

另外,在调试时,我发现我的 ViewModel 中的 mapType val 没有观察者(不确定这是对还是错,只是很有趣)

最佳答案

这里的问题是,尽管绑定(bind)到 mapLabel 字段,但当 mapLabel 字段的值更改时, View 绑定(bind)并未更新。

原因是我没有在绑定(bind)上设置生命周期所有者。

binding.setLifecycleOwner(this)

阅读this blog post后我意识到我的错误第 10 次。

我的新 MapsActivity.kt

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap
    private lateinit var viewModel: MapViewModel
    private lateinit var binding: ActivityMapsBinding

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_maps)
        binding.setLifecycleOwner(this) //<- NEW!
        viewModel = ViewModelProviders.of(this).get(MapViewModel::class.java)
        binding.vm = viewModel

        val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        // Here is where i'm setting the MapType on the ViewModel.
        viewModel.mapType.value = MapType.MAP
    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap
    }
}

从好的方面来说,我学到了很多关于 LiveData 内部工作原理的知识!

关于android - 来自 Transformation 的数据绑定(bind) LiveData - Android Kotlin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49551851/

相关文章:

android - 我应该让 AsyncTask 成为 LiveData 或 Repository 类的成员 - 作为 Loader 的替代品

android - 从 fragment 中的按钮单击打开抽屉导航(Kotlin)

java - Kotlin Arraylist 与 Java Arraylist 的类型不匹配

Android房间迁移null报错

android - LiveData 双向数据绑定(bind),无需公开 MutableLiveData

linq - Kotlin 中的语言集成查询?

Android:SectionIndex 对话框的自定义布局

java - 迁移AndroidX运行报错android.support.annotation does not exist

android - 出现键盘时 Webview 不调整大小

java - Android:使用 findViewById(ID) 时的静态引用/非静态方法