Home > front end >  State Holder in jetpack compose
State Holder in jetpack compose

Time:10-06

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.

  • Related