Edit: Apologies for the title, it should be specified (mutableStateObject triggers re-composition even if not being read/observed), please edit if necessary.
This issue I encountered comes from a use-case where I deal with java.time components and I found out it has something to do with static references, so I decided to create 2 Java classes that are being used in some composables
RootJavaClass
public class RootJavaClass {
public static AnotherJavaClass getNewInstance() {
return new AnotherJavaClass("Hello There");
}
}
AnotherJavaClass
public class AnotherJavaClass {
public String data = "";
public AnotherJavaClass(String param) {
data = param;
}
}
My Parent Scope Composable
@Composable
internal fun ParentComposable(
modifier: Modifier = Modifier
) {
var stateLessObject = RootJavaClass.getNewInstance()
var mutableStateObject by remember { mutableStateOf(stateLessObject)}
Column(
modifier = Modifier.fillMaxSize()
) {
DoesNotReadAnyMutableState(stateLessObject = stateLessObject) {
mutableStateObject = it
}
ReadsAMutableState(mutableStateObject)
}
}
and lastly some child composable inside the parent scope
@Composable // this composable is being re-composed unwantedly
fun DoesNotReadAnyMutableState(
stateLessObject : AnotherJavaClass,
onButtonClick : (AnotherJavaClass) -> Unit
) {
Button(
onClick = {
onButtonClick(AnotherJavaClass("GoodBye"))
},
) {
Text(
text = stateLessObject.data
)
}
}
@Composable
fun ReadsAMutableState(
mutableStateObject: AnotherJavaClass
) {
Text(
text = mutableStateObject.data
)
}
Why does the DoesNotReadAnyMutableState composable is being re-composed? even if it doesn't read the mutableState object?, this does not happen with ordinary classes even with String. This only happens when I use static referenced object, set it to be remembered as the initial value of the mutable state object and modify that object ( as you can see in the lambda callback )
Thank you in advance..
Edit: I made some changes referencing the answer from another post regarding Smart Re-composition, credits to @Thracian Smart Re-composition
I created my own non-inlined Column{..} scope
@Composable
fun MyOwnColumnScope(content: @Composable () -> Unit) {
Column(
modifier = Modifier.fillMaxSize()
) {
content()
}
}
and used it this way
MyOwnColumnScope {
DoesNotReadAnyMutableState(stateLessObject = stateLessObject) {
mutableValue = it
}
ReadsAMutableState(mutableValue)
}
but it still triggers the un-wanted recomposition :(
I'm not quite sure if there's a special case within the usage of statics, or if this is a bug within the snapshot`compose` framework?

