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
CodePudding user response:
Ill try my best here man, 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 case, ViewModel
, and lifecyle
is something you have to be aware of.
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)
CodePudding user response:
In my opinion, the best thing to do to deeply learn new material is to take notes and read examples, not to directly ask for help from others. Of course, when you don't help yourself in learning, no one will help you. I can only tell you this about your code, that it is read State Holder
more closely.