Pauel3312
Pauel3312

Reputation: 92

How can I update the value I draw with Jetpack Compose?

I am trying to do an android app that gets and displays the battery percentage, but I can't get it to update.

I tried using the function updateBatteryPct but because it has a delay (else it crashes) it is registered as suspend it cannot be used in onCreate because making onCreate suspend causes it to not be an override anymore. This is one of my many tries to update this value, I am not even sure that updateBatteryPct will even work. I would appreciate if someone could explain me in depth how this works bc I dont understad really everything. I can code in Kotlin and do stuff but I can't do anything that works for android.

class MainActivity : ComponentActivity() {
    var batteryStatus: Intent? = null
    var batteryPct: MutableState<Int> = mutableStateOf(0)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(/* savedInstanceState = */ savedInstanceState)
        setContent {
            this.batteryStatus = getBatteryStatusReceiver()
            this.batteryPct = remember {
                mutableStateOf(0)
            }
            BatterySaverAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
                    getBatteryPct(this.batteryStatus, this.batteryPct)
                    DisplayBatteryPercentage(batteryPercentage = this.batteryPct)
                }
            }
        }
        }
        suspend fun updateBatteryPct () {
            while (true) {
                getBatteryPct(this.batteryStatus, this.batteryPct)
                delay(1000)
                Log.d("customTest", "updateBatteryPct: Looping")
            }
        }
    }

    class BatteryManagerBroadcastReceiver(
        private val onReceiveIntent: (Intent) -> Unit,
    ) : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            onReceiveIntent(intent)
        }
    }
    @Composable
    fun updateBatteryPct(batteryStatus: Intent?, batteryPct: MutableState<Int>) {
        while (true) {
            getBatteryPct(batteryStatus, batteryPct)
            DisplayBatteryPercentage(batteryPercentage = batteryPct)
        }
    }


    fun getBatteryPct(batteryStatus: Intent?, batteryPct: MutableState<Int>){
        batteryPct.value =  batteryStatus?.let { intent ->
            val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
            val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
            level * 100 / scale
        }!!
    }

    @Composable
    fun getBatteryStatusReceiver(): Intent? {
        val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
            LocalContext.current.applicationContext.registerReceiver(null, ifilter)
        }
        return batteryStatus
    }

    @Composable
    fun DisplayBatteryPercentage(batteryPercentage: MutableState<Int>) {
        Column(Modifier.padding(16.dp)) {
            Text("battery is at ${batteryPercentage.value}%") }
    }

Upvotes: 1

Views: 651

Answers (2)

user2698872
user2698872

Reputation: 1

var battery by rememberSaveable { mutableStateOf(0) }

Upvotes: 0

Gabriele Mariotti
Gabriele Mariotti

Reputation: 364730

It is better to register the BroadcastReceiver with a side effect.

Something like:

@Composable
fun SystemBroadcastReceiver(
    systemAction: String,
    onSystemEvent: (intent: Intent?) -> Unit
) {
    // Grab the current context in this part of the UI tree
    val context = LocalContext.current

    // Safely use the latest onSystemEvent lambda passed to the function
    val currentOnSystemEvent by rememberUpdatedState(onSystemEvent)

    // If either context or systemAction changes, unregister and register again
    DisposableEffect(context, systemAction) {
        val intentFilter = IntentFilter(systemAction)
        val broadcast = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                currentOnSystemEvent(intent)
            }
        }

        context.registerReceiver(broadcast, intentFilter)

        // When the effect leaves the Composition, remove the callback
        onDispose {
            context.unregisterReceiver(broadcast)
        }
    }
}

Then in your composable just update the value:

var battery by remember { mutableStateOf(0) }

SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus ->
    val batteryPct: Float? = batteryStatus?.let { intent ->
        val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
        val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        level * 100 / scale.toFloat()
    }
    battery = batteryPct!!.toInt()
}

Upvotes: 3

Related Questions