I want to know that why we cannot use delegate property in mutableStateListOf
. When I am trying to add
val favourites by remember { mutableStateListOf<Int>() }
It gives me error
Type 'TypeVariable(T)' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate
Also I tried to imports
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
but it stills gives the same error. Is there any specific reason for this? Thanks
CodePudding user response:
What you should be asking is how do i use mutableStateOf
with delegation because delagation is not part of any class by default.
MutableState delegation is implemented as
/**
* Permits property delegation of `val`s using `by` for [State].
*
* @sample androidx.compose.runtime.samples.DelegatedReadOnlyStateSample
*/
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value
/**
* Permits property delegation of `var`s using `by` for [MutableState].
*
* @sample androidx.compose.runtime.samples.DelegatedStateSample
*/
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
this.value = value
}
/**
* A mutable value holder where reads to the [value] property during the execution of a [Composable]
* function, the current [RecomposeScope] will be subscribed to changes of that value. When the
* [value] property is written to and changed, a recomposition of any subscribed [RecomposeScope]s
* will be scheduled. If [value] is written to with the same value, no recompositions will be
* scheduled.
*
* @see [State]
* @see [mutableStateOf]
*/
@Stable
interface MutableState<T> : State<T> {
override var value: T
operator fun component1(): T
operator fun component2(): (T) -> Unit
}
Functions you import with
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
are getValue
and setValue
functions in snippet above.
You can create delegation functions for classes as extension functions which require you to import them or as part of class as in examples below.
class CalculateDelegate {
private var calculatedProperty = 0
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return calculatedProperty
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
calculatedProperty = value * 2
}
}
/**
* Delegate [CalculateDelegate] to this function
*/
fun delegateCalculationFunction() = CalculateDelegate()
If you create a instances using
var delegatedNum1 by CalculateDelegate()
var delegatedNum2 by delegateCalculationFunction()
And then if you change or call setValue as
delegatedNum1 = 4
delegatedNum2 = 3
if you print these delegateNum1, and delegateNum2 you will see that they are 8 and 6 because of overriding setValue
If you wish to force overriding setValue and getValue functions for a class you can use ReadWriteProperty as
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
Then you need to override getValue
and setValue
functions.
class CalculateDelegate: ReadWriteProperty<Any?, Int> {
private var calculatedProperty = 0
override operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return calculatedProperty
}
override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
calculatedProperty = value * 2
}
}