I have chat like interface in Jetpack compose. Every message can either be Text, Audio, Video, or Image.
Each Audio message is displayed with the help of a AudioPlayer composable, and an attached controller to it. The screen ViewModel has a single instance of AudioPlayerController, and each component collects its state from that controller's StateFlow<UiState>
. UiState contains states like audioFilePath, fileName, duration, progress, etc. I'm determining which player of the state is playing based on the filePath.
@Composable
fun AudioPlayerUi(audioFilePath:String, ...) {
val uiState by controller.uiState.collectAsState()
val isPlaying by remember { derivedStateOf { audioFilePath == uiState.audioFilePath } }
...
}
And there are many more components on the screen which have similar logic.
My question is how good is it if my controller extends ViewModel and I create an instance of that controller in each component?
@Composable
fun AudioPlayerUi(audioFilePath:String, ...) {
val controller by viewModel<AudioPlayerController>()
val uiState by controller.uiState.collectAsState()
val isPlaying = uiState.isPlaying
...
}
Now there are more questions following it.
My Scrren is something like:
ReceivedText
ReceivedAudio
SentText
SentAudio
SentImage
ReceivedImage
SentText
ReceivedAudio
ReceivedImage
SentAudio
SentImage
##### INPUT WIDGETS #####
##### Can be any one ####
TestInput, AudioRecorder,
Camera, etc
#########################
Each sent component has editing feature as well.
I read most articles and documentations available online, but none of them mentions about having each component having it's vieeModel. Also I can't have all the logic in screen ViewModel because each controller is big in itself.
This is an opinion-based question.
(So the answer is aligned with the opinions of Android team recommendations)
To give an answer from Android Docs, Reference - https://developer.android.com/jetpack/compose/state-hoisting#screen-ui-state
Use ViewModel
as a screen UI state holder.
Using ViewModel
for each component does not have any additional benefits and it is an additional overhead.
The following issues can happen,
init
can happen way earlier for some components, etc).For individual components, you can use a simple class as a StateHolder or move to a screen-level ViewModel if required to use business logic.
How to choose State Holder in a simple way.
To add on, as mentioned in the starting, this is an opinionated question and hence an opinionated answer. You can use ViewModel for the Component level if you see it is required and you are careful to handle all the issues related to it.