Это экран видеовызова. Для работы ему нужен токен и имя канала, которые необходимо передать механизму вызова инициализации. Я храню их в классе данных, который используется как изменяемое состояние.
Класс данных состояния экрана
@Keep
data class CallScreenState(
val callerId: Int? = null,
val recieverId: Int? = null,
val chatRoom: ChatRoom.Data? = null,
val rtcToken: AgoraTokenResponse.TokenData? = null
)
И в состоянии инициализации viewmodel по этому коду:
var callScreenState by mutableStateOf(CallScreenState())
и в модели просмотра при успешном ответе чата и API токена состояние обновляется с помощью этого кода.
callScreenState = callScreenState.copy(
chatRoom = chatRoom.data,//from response
rtcToken = token.data //from response
)
Отсюда ожидается перекомпоновка экрана с новым обновленным значением chatRoom и 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 для получения токена и чата дает успех, состояние экрана обновляется из модели представления, и я ожидаю, что удовольствие initEngine будет вызвано снова, поскольку оно должно перекомпоновываться. Но это не так. Я что-то упускаю ? Как заставить его перекомпоновываться при изменении значения имени канала внутри экрана?
Я не могу понять весь ваш вариант использования, но вы пытались указать key на свой remember?
Как заставить его перекомпоновываться, когда значение имени канала находится внутри экрана изменения?
Вы можете попробовать любой из них, хотя я не уверен, решат ли они вашу проблему, но когда вы вводите key в remember и он изменяется, он будет re-calculate, предполагая, что channelName, который использовался в предыдущем расчете remember's, будет другим на следующий re-composition.
Этот,
val screenState = remember(key1 = channelname) {
viewModel.callScreenState
}
или это
val mEngine = remember(key1 = channelname) { ... }
Идеально! Это решило проблему, у меня не было ключа внутри. Большое спасибо @z.y