来自转换的数据绑定 LiveData - Android Kotlin
Data binding LiveData from Transformation - Android Kotlin
我正在学习 kotlin 和 android 架构组件。
我在 google 地图上有一个地图切换按钮的简单用例。
我想使用数据绑定将地图切换按钮标签绑定到我的 ViewModel 中的 MutableLiveData 字段。
我通过 Activity 中的 onCreate 方法在 MapViewModel 中设置了 mapType val。如果我理解正确,这应该会触发 mapLabel val 由于使用 Transformations.map 而发生变化。
它不工作...为什么?
这是我的版本:
- Android 工作室 3.2 金丝雀 4
- kotlin_version = '1.2.21'
- 支持 = "27.1.0"
- arch_core = "1.1.0"
- databinding = "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 对象的绑定,我在 activity 中设置了字符串,它工作正常。问题似乎出在 Transformations.map - 我只是理解错了吗?
此外,在调试时,我看到我的 ViewModel 中的 mapType val 没有观察者(不确定这是对还是错,只是有趣)
Its not working... Why?
当您更改 mapType
的值时,mapLabel
的值不会立即更改。您需要重新设置 mapLabel
的值。例如,在为 mapType
设置值后,调用方法来更新 mapLabel
的值
// Here is where i'm setting the MapType on the ViewModel.
viewModel.mapType.value = MapType.MAP
viewModel.updateMapLabel()
您的视图模型:
fun updateMapLabel() {
mapLabel.value =
if (it == MapType.MAP) "SAT" else "MAP"
}
这里的问题是,尽管绑定到 mapLabel
字段,但当 mapLabel
字段的值更改时,视图绑定不会更新。
原因是我没有在绑定上设置生命周期所有者。
binding.setLifecycleOwner(this)
第10次阅读this blog post后我意识到我的错误。
我的新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 内部工作原理的知识!
我正在学习 kotlin 和 android 架构组件。 我在 google 地图上有一个地图切换按钮的简单用例。
我想使用数据绑定将地图切换按钮标签绑定到我的 ViewModel 中的 MutableLiveData 字段。
我通过 Activity 中的 onCreate 方法在 MapViewModel 中设置了 mapType val。如果我理解正确,这应该会触发 mapLabel val 由于使用 Transformations.map 而发生变化。
它不工作...为什么?
这是我的版本:
- Android 工作室 3.2 金丝雀 4
- kotlin_version = '1.2.21'
- 支持 = "27.1.0"
- arch_core = "1.1.0"
- databinding = "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 对象的绑定,我在 activity 中设置了字符串,它工作正常。问题似乎出在 Transformations.map - 我只是理解错了吗?
此外,在调试时,我看到我的 ViewModel 中的 mapType val 没有观察者(不确定这是对还是错,只是有趣)
Its not working... Why?
当您更改 mapType
的值时,mapLabel
的值不会立即更改。您需要重新设置 mapLabel
的值。例如,在为 mapType
设置值后,调用方法来更新 mapLabel
// Here is where i'm setting the MapType on the ViewModel.
viewModel.mapType.value = MapType.MAP
viewModel.updateMapLabel()
您的视图模型:
fun updateMapLabel() {
mapLabel.value =
if (it == MapType.MAP) "SAT" else "MAP"
}
这里的问题是,尽管绑定到 mapLabel
字段,但当 mapLabel
字段的值更改时,视图绑定不会更新。
原因是我没有在绑定上设置生命周期所有者。
binding.setLifecycleOwner(this)
第10次阅读this blog post后我意识到我的错误。
我的新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 内部工作原理的知识!