这是一个视频通话屏幕。它需要令牌和通道名称才能工作,这需要传递给init调用引擎。我将这些存储在一个用作可变状态的数据类中。
屏幕状态数据类
@Keep
data class CallScreenState(
val callerId: Int? = null,
val recieverId: Int? = null,
val chatRoom: ChatRoom.Data? = null,
val rtcToken: AgoraTokenResponse.TokenData? = null
)
并且在视图模型初始化状态下通过以下代码:
var callScreenState by mutableStateOf(CallScreenState())
在聊天室和令牌api的成功响应视图模型中,状态会用这段代码更新。
callScreenState = callScreenState.copy(
chatRoom = chatRoom.data,//from response
rtcToken = token.data //from response
)
从这里开始,预计将使用聊天室和rtcToken的新更新值重新组合屏幕
在可组合中
val screenState = remember {
viewModel.callScreenState
}
该屏幕状态用于将值传递给初始化引擎
val mEngine = remember {
initEngine(
context,
object : IRtcEngineEventHandler() {
override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
Timber.e("hhp-CallScreen onJoinChannelSuccess channel:$channel,uid:$uid,elapsed:$elapsed")
}
override fun onUserJoined(uid: Int, elapsed: Int) {
Timber.e("hhp-CallScreen onUserJoined:$uid")
val desiredUserList = remoteUserMap.toMutableMap()
desiredUserList[uid] = null
remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
}
override fun onUserOffline(uid: Int, reason: Int) {
Timber.e("hhp-CallScreen onUserOffline:$uid")
val desiredUserList = remoteUserMap.toMutableMap()
desiredUserList.remove(uid)
remoteUserMap = desiredUserList.toMap() as HashMap<Int, TextureView?>
}
override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
Timber.e("hhp-CallScreen onNetworkQuality $uid $txQuality $rxQuality")
}
},
screenState.chatRoom?.channelName ?: "", //Not recomposing when value changes in viewmodel
viewModel.userRole,
token = screenState.rtcToken?.token ?: "" //Not recomposing when value changes in viewmodel
)
}
这是initEngine函数创建
fun initEngine(
current: Context,
eventHandler: IRtcEngineEventHandler,
channelName: String,
userRole: String,
token: String
): RtcEngine =
RtcEngine.create(current, BuildConfig.AGORA_APPID, eventHandler).apply {
enableVideo()
setChannelProfile(1)
if (userRole == "Broadcaster") {
setClientRole(1)
} else {
setClientRole(0)
}
//Expected to be recomposed when screen state value updated with new values
joinChannel(token, channelName, "", 0)
}
我一开始就知道,在api调用之前,屏幕状态中的通道名称和令牌是空的。一旦获取令牌和聊天室的api成功,屏幕状态就会从viewmodel更新,我希望initEngine fun会再次被调用,因为它应该会重新组合。但事实并非如此。我是不是错过了什么?当屏幕状态内的频道名称值发生变化时,如何重新组合?
我无法理解您的整个用例,但您是否尝试过将key
指定为remember
?
如何在屏幕内更改频道名称值时重新组合sctate更改?
您可以尝试其中任何一种,尽管我不确定它们是否能解决您的问题,但当您将key
提供给remember
并且它发生更改时,它将为re-calculate
,假设remember's
之前计算使用的channelName
在下一个re-composition
上会有所不同。
这个,
val screenState = remember(key1 = channelname) {
viewModel.callScreenState
}
或者这个
val mEngine = remember(key1 = channelname) { ... }