简体   繁体   中英

State Holder in jetpack compose

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM