android 状态值更改时屏幕未重组- Jetpack Compose

mqkwyuun  于 2022-11-03  发布在  Android
关注(0)|答案(1)|浏览(262)

这是一个视频呼叫屏幕。它需要令牌和通道名称来工作,需要传递到初始化调用引擎。我将这些存储在一个数据类中,用作可变状态。
屏幕状态数据类

  1. @Keep
  2. data class CallScreenState(
  3. val callerId: Int? = null,
  4. val recieverId: Int? = null,
  5. val chatRoom: ChatRoom.Data? = null,
  6. val rtcToken: AgoraTokenResponse.TokenData? = null
  7. )

而在viewmodel中初始化状态由以下代码实现:

  1. var callScreenState by mutableStateOf(CallScreenState())

并且在聊天室和令牌API的成功响应上的视图模型中,用该代码更新状态。

  1. callScreenState = callScreenState.copy(
  2. chatRoom = chatRoom.data,//from response
  3. rtcToken = token.data //from response
  4. )

从此处开始,预计将使用chatRoom和rtcToken的新更新值重新组成屏幕。

而在可组合

  1. val screenState = remember {
  2. viewModel.callScreenState
  3. }

此屏幕状态用于将值传递到init引擎

  1. val mEngine = remember {
  2. initEngine(
  3. context,
  4. object : IRtcEngineEventHandler() {
  5. override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
  6. Timber.e("hhp-CallScreen onJoinChannelSuccess channel:$channel,uid:$uid,elapsed:$elapsed")
  7. }
  8. override fun onUserJoined(uid: Int, elapsed: Int) {
  9. Timber.e("hhp-CallScreen onUserJoined:$uid")
  10. val desiredUserList = remoteUserMap.toMutableMap()
  11. desiredUserList[uid] = null
  12. remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
  13. }
  14. override fun onUserOffline(uid: Int, reason: Int) {
  15. Timber.e("hhp-CallScreen onUserOffline:$uid")
  16. val desiredUserList = remoteUserMap.toMutableMap()
  17. desiredUserList.remove(uid)
  18. remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
  19. }
  20. override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
  21. Timber.e("hhp-CallScreen onNetworkQuality $uid $txQuality $rxQuality")
  22. }
  23. },
  24. screenState.chatRoom?.channelName ?: "", //Not recomposing when value changes in viewmodel
  25. viewModel.userRole,
  26. token = screenState.rtcToken?.token ?: "" //Not recomposing when value changes in viewmodel
  27. )
  28. }

这是initEngine函数的创建

  1. fun initEngine(
  2. current: Context,
  3. eventHandler: IRtcEngineEventHandler,
  4. channelName: String,
  5. userRole: String,
  6. token: String
  7. ): RtcEngine =
  8. RtcEngine.create(current, BuildConfig.AGORA_APPID, eventHandler).apply {
  9. enableVideo()
  10. setChannelProfile(1)
  11. if (userRole == "Broadcaster") {
  12. setClientRole(1)
  13. } else {
  14. setClientRole(0)
  15. }
  16. //Expected to be recomposed when screen state value updated with new values
  17. joinChannel(token, channelName, "", 0)
  18. }

我知道在最开始的时候,屏幕状态中的通道名称和令牌在api调用之前是空的。一旦api用于获取令牌和聊天室成功,屏幕状态将从viewmodel更新,我希望initEngine功能将被再次调用,因为它应该重新组合。但事实并非如此。我是否遗漏了什么?如何在屏幕状态中的通道名称值发生变化时重新组合?

pdtvr36n

pdtvr36n1#

我不能理解您的整个用例,但是您是否尝试过将key指定给您的remember
如何在屏幕状态中的channelname值改变时重新组合?
您可以尝试这两种方法中的任何一种,虽然我不确定它们是否能解决您的问题,但是当您向remember提供一个key时,它发生了变化,它将是re-calculate,假设remember's先前计算所使用的channelName在下一个re-composition中将是不同的。
这,

  1. val screenState = remember(key1 = channelname) {
  2. viewModel.callScreenState
  3. }

或此

  1. val mEngine = remember(key1 = channelname) { ... }

相关问题