I am learning in State in jetpack compose. I found that State holders as source of truth. So created my some data can you guys guide me if I am doing wrong here.
PairViewModel.kt
class PairViewModel : ViewModel() {
var isBluetoothEnabled = mutableStateOf(false)
private set
fun onBluetoothEnable(value: Boolean) {
isBluetoothEnabled.value = value
}
}
PairScreen.kt
class PairScreenState(context: Context, viewModel: PairViewModel) {
private val bluetoothManager: BluetoothManager = context.getSystemService(BluetoothManager::class.java)
private val bluetoothAdapter: BluetoothAdapter by lazy {
bluetoothManager.adapter
}
init {
viewModel.onBluetoothEnable(bluetoothAdapter.isEnabled)
}
fun checkBluetoothStatus(bluetoothStatus: MutableState<Boolean>): BroadcastReceiver {
return object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
when (intent.getIntExtra(
BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR
)) {
BluetoothAdapter.STATE_OFF -> {
bluetoothStatus.value = false
}
BluetoothAdapter.STATE_ON -> {
bluetoothStatus.value = true
}
}
}
}
}
}
}
@Composable
fun rememberPairScreenState(
context: Context,
viewModel: PairViewModel
) = remember {
PairScreenState(context, viewModel)
}
@Composable
fun PairContent(
context: Context = LocalContext.current,
viewModel: PairViewModel = getViewModel(),
rememberPairScreenState: PairScreenState = rememberPairScreenState(context, viewModel),
) {
AnimatedVisibility(visible = true) {
AppBarScaffold() {
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
rememberPairScreenState.checkBluetoothStatus(viewModel.isBluetoothEnabled).apply {
context.registerReceiver(this, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
}
if (viewModel.isBluetoothEnabled.value) {
println(">> Enable >>>")
} else {
println(">> Disable >>>")
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun PairContentPreview() {
PairContent()
}
I am using Bluetooth as example to understand state holder in my use case. Please guide me if you find anything wrong in my code. Thanks
Ill try my best here, I get where you're coming from, having a code that it's hard to verify if its the proper way of doing "yet", regardless of how many source materials you review like in github, sometimes references just doesn't exist yet right?
For State hoisting/handling, its good to follow the principles coming from the community. So the way I handle State Hoisting, is thinking of its purpose
So if its just something that needs to be local within the @Composable
remember {...}
If its something that deals with multiple logic and values, State class
class PersonState(val personParam: Person) {
.....
}
@Composable
fun rememberPersonState(person: Person) = remember(key1= person) {
PersonState(person)
}
If its something that deals with repository, network calls, use-cases where persistence is a major part of the requirement, ViewModel, and lifecyle is something you have to be aware of. ViewModel
class PersonScreenViewModel {
/..RepositoryStateFlows../
/..Data structural updates../
}
So far this mindset and approach helped me a bit when deciding how would I hoist my states.
As for your PairScreenState, consider this use-case solution coming from this post Detect if Soft Keyboard is Open or Close, where you can detect if the keyboard is open or not
I would have your BlueTooth usecase where I would implement it as a Composable utility function and returns a State where I can define a DisposableEffect, though this code is not working but I think you'll get my point here.
enum class BlueTooth {
ON, OFF
}
@Composable
fun BlueToothAsState(): State<BlueTooth> {
val blueToothState = remember { mutableStateOf(BlueTooth.OFF) }
DisposableEffect(view) {
var mReceiver : BroadcastReceiver? = object : BroadcastReceiver() {
/.../
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
BluetoothAdapter.STATE_OFF -> {
blueToothState = BlueTooth.OFF
}
BluetoothAdapter.STATE_ON -> {
blueToothState = BlueTooth.ON
}
}
}
}
onDispose {
mReceiver = null
}
}
return blueToothState
}
As for the other parts of the code, I don't think you need it here if its just always set to true
AnimatedVisibility(visible = true)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With