【发布时间】:2021-03-13 17:01:50
【问题描述】:
我有一个包含 googleMap 的片段,我在其中创建了一堆标记(也是可点击的)。它们添加了来自房间实时数据查询的不同信息(颜色、形状等)。此外,我还有一些 MaterialButton 按钮(样式为按钮),我可以在其中切换标记可见状态。目前,这些标记的“设置”需要一些时间(200ms-2 秒,取决于标记的数量)。为了摆脱这种等待,我打算使用 viewmodelscope。由于其中定义了这些按钮的一些点击侦听器(它们应该对标记执行一些操作),当 viewmodelscope 协程部分结束时它们是否仍然存在,如果它们还存在,它们是否仍然存在于正确的协程上下文中,当片段和/或视图模型结束时,我是否需要对侦听器进行一些整理?
IE:
class MapsFragment:Fragment(){
private lateinit var mapsViewModel : MapsViewModel
private lateinit var googleMap : GoogleMap
//...
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mapsViewModel = ViewModelProvider(requireActivity()).get(MapsViewModel::class.java)
_binding = FragmentMapsBinding.inflate(inflater, container, false)
val root:View = binding.root
//...
return root
}//onCreateView
//...
override fun onViewCreated(view: View, savedInstanceState:Bundle?){
super.onViewCreated(view, savedInstanceState)
//...
mapFragment?.getMapAsync(_googleMap->
_googleMap?.let{safeGoogleMap->
googleMap = safeGoogleMap
}?:let{
Log.e(TAG,"googleMap is null!!")
return@getMapAsync
}
//...
mapsViewModel.apply{
liveDataMapsListFromFiltered?.observe(
viewLifecycleOwner
){mapDetailList->
viewModelScope.launch{
binding.apply{
//...
siteMarkers.map{
siteMarker.remove() //removes existing markes from map on update
}
siteMarkers.clear() //empty the siteMarker array on update
//...
mapDetailList?.map{
it.apply{
//...
coordinateSiteLongitude?.let { lng->
coordinateSiteLatitude?.let { lat->
siteMarkerLatLng = LatLng(lat,lng)
siteLatLngBoundsBuilder?.include(siteMarkerLatLng)
}
}
//...
siteMarkerLatLng?.let { safeSiteMarkerLatLng ->
val siteMarkerOptions =
MarkerOptions()
.position(safeSiteMarkerLatLng)
.anchor(0.5f, 0.5f)
.visible(siteMarkerState)
.flat(true)
.title(setTicketNumber(ticketNumber?.toDouble()))
.snippet(appointmentName)//TODO: Consider build siteId instead
.icon(siteIcon[iconType])
siteMarkers.add(
googleMap.addMarker(siteMarkerOptions) //Here are the markers added
)
}//siteMarkerLatLng?.let
}//it.apply
}//mapDetailList?.map
onSiteCheckedChangeListener?.let{
fragmentMapsMapTagSelector
?.apTagSelectorMaterialButtonSite
?.removeOnCheckedChangeListener(it) //clearing listener on button before update
}
onSiteCheckedChangeListener = MaterialButton.OnCheckedChangeListener { siteButton, isChecked ->
siteMarkers.map {
it.isVisible = isChecked
}
}.also {
fragmentMapsMapTagSelector
?.mapTagSelectorMaterialButtonSite
?.addOnCheckedChangeListener(it)
}
//Will this onCheckedChangeListener still survive when this viewmodelscope runs to the end ?
}//binding.apply
}//viewModelScope.launch
}//liveDataMapsListFromFiltered.observe
}//mapsviewModel.apply
}//getMapAsync
}//onViewCreated
}//MapsFragment
【问题讨论】:
-
“viewmodelscope 走到尽头”是什么意思? ViewModel 有一个名为
viewModelScope的属性,它是一个用于运行协程的 CoroutineScope,与您显示的代码无关。您已经在 Activity 的生命周期中检索了 ViewModel,因此 ViewModel 的生命周期将与托管此 Fragment 的 Activity 的生命周期相匹配。 -
我实际上忘记了 viewmodelscope 行...抱歉,我会尽快重新整理我的 Q。
-
然后我添加了
viewModelScope.launch。通过这样做,我希望在设置标记并准备就绪时避免延迟。隐藏/取消隐藏可以很好地使用每个标记的可见参数(在观察按钮上的选中更改时通过它们进行迭代)。但我担心通过使用这个 viewmodelscope,当 viewmodelscope 结束时“基础”不存在,所以当片段死亡时,片段不会杀死按钮上的 onchangelisteners。 -
...或者我是否需要一些“聪明的”
withContext钳制,例如viewModelScope.launch中的第一个withContext(Dispatchers.Default){ ... }并在每次写入 View 后代时使用withContext(Dispatcher.Main){...}对其进行调味。顺便说一句:您可以读取带有 Dispatchers.Main 上下文的视图(或后代)(不影响(更改)用户界面吗?)。 -
... 以及如何最好地停止这些协程。我已将我的视图模型绑定到 Activity 而不是 Fragment。所以我可能对视图模型的寿命超过片段有问题,并且当片段死亡时,对视图 vil 的引用无效,因为视图模型仍然活着(?)。
标签: google-maps kotlin android-room kotlin-coroutines android-viewmodel