【问题标题】:LiveData Transformation not getting triggeredLiveData 转换未触发
【发布时间】:2018-03-16 14:06:46
【问题描述】:

我在 ui 中订阅了 idssearch,但没有得到任何结果,所以我逐步调试了调试器,发现在第一次之后没有触发转换。因此,当我第一次调用setIds 时,ids 会更新,但在第一次调用之后的每次调用都不会触发转换。 search 也是如此。

有什么想法可能会出错吗?

class MyViewModel : ViewModel() {

    private val repository = Repository.sharedInstance

    var recentRadius: LiveData<List<RecentRadius>>?
    var recentRoute: LiveData<List<RecentRoute>>?

    init {
        recentRadius = repository.recentRadius()
        recentRoute = repository.recentRoute()
    }


    private val idsInput = MutableLiveData<String>()
    fun setIdsInput(textId: String) {
        idsInput.value = textId
    }

    val ids: LiveData<List<String>> = Transformations.switchMap(idsInput) { id ->
        repository.ids(id)
    }

    private val searchInput = MutableLiveData<Search>()
    fun setSearchInput(search: Search) {
        searchInput.value = search
    }


    val search: LiveData<SearchResult> = Transformations.switchMap(searchInput) { search ->
        when (search.type) {
            SearchType.ID -> repository.id(search)
            SearchType.RADIUS -> repository.radius(search)
            SearchType.ROUTE -> repository.route(search)
        }
    }
}

【问题讨论】:

  • 转换没有被触发的最常见原因是没有Observer观察它或者输入LiveData没有改变。
  • @AkshayChordiya 谢谢这帮助我解决了我的问题。我在他们的onCreate() 中注册了我的片段,但我切换了它们,导致观察者迷路了。
  • 我会将其发布为答案,以便其他人能够找到根本原因

标签: android-room android-livedata


【解决方案1】:

没有触发转换的最常见原因是没有Observer 观察它或输入LiveData 没有改变。

【讨论】:

  • 虽然 Fragment/Activity 订阅了 ids 更新,为什么转换需要另一个观察者触发?我不明白这里的那部分。为什么我必须订阅idsInput LiveData 才能使transformation 工作?
  • Transformations 被设计为,它们将主线程上的给定函数应用于source LiveData 发出的每个值。这意味着传递的函数只有在值发生变化时才会执行。
  • 但是当您第一次附加观察者时它们不会触发。它们仅在值更改时触发。
【解决方案2】:

以下示例说明了在活动中附加观察者时地图的使用。

活动

class MainActivity : AppCompatActivity() {

lateinit var mBinding : ActivityMainBinding

private val mViewModel : MainViewModel by lazy {
   getViewModel { MainViewModel(this.application) }
}

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
   mBinding.vm = mViewModel

   // adding obeserver
   mViewModel.videoName.observe(this, Observer<String> { value ->
       value?.let {
           //Toast.makeText(this, it, Toast.LENGTH_LONG).show()
       }
   })
 }
}

ViewModel 带地图

class MainViewModel(val appContext : Application) : AndroidViewModel(appContext) {

   private val TAG = "MainViewModel"

   var videoData = MutableLiveData<VideoDownload>()
   var videoName : LiveData<String>

   init {
      // Update the data
      videoName = Transformations.map(videoData) { "updated : "+it.webUrl }
    }

    fun onActionClick(v : View) {
       // change data
       videoData.value = VideoDownload(System.currentTimeMillis().toString())
    }

    fun onReActionClick(v : View) {
       // check data
       Toast.makeText(appContext, videoName.value, Toast.LENGTH_LONG).show()
    }

}

ViewModel 和 switchMap

class MainViewModel(val appContext : Application) : AndroidViewModel(appContext) {

    private val TAG = "MainViewModel"

    var videoData = MutableLiveData<VideoDownload>()
    var videoName : LiveData<String>

    init {
       // Update the data
       videoName = Transformations.switchMap(videoData) { modData(it.webUrl) }

    }

    private fun modData(str: String): LiveData<String> {
        val liveData = MutableLiveData<String>()
        liveData.value = "switchmap : "+str
        return liveData
    }

    fun onActionClick(v : View) {
        // change data
        videoData.value = VideoDownload(System.currentTimeMillis().toString())
    }

    fun onReActionClick(v : View) {
        // check data
        Toast.makeText(appContext, videoName.value, Toast.LENGTH_LONG).show()
    }

}

【讨论】:

    【解决方案3】:

    对我来说,这是因为观察者所有者是一个片段。导航到不同的片段时它停止触发。我将观察者所有者更改为活动,它按预期触发。

    itemsViewModel.items.observe(requireActivity(), Observer {
    

    视图模型被定义为类属性:

        private val itemsViewModel: ItemsViewModel by lazy {
        ViewModelProvider(requireActivity()).get(ItemsViewModel::class.java)
    }
    

    【讨论】:

      【解决方案4】:

      如果你真的希望它被触发。

      fun <X, Y> LiveData<X>.forceMap(
          mapFunction: (X) -> Y
      ): LiveData<Y> {
          val result = MutableLiveData<Y>()
          this.observeForever {x->
              if (x != null) {
                  result.value = mapFunction.invoke(x)
              }
          }
          return result
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-06-12
        • 1970-01-01
        • 2019-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多