-1

I want to calculate height of Box in a function and I want compose to remember its result and not call that function again. That function has some composable content and therefore it is a @Composable function.

The problem is that, Compose won't let me call this function from remember block.

This is the code that I have:

val coverImageHeightInDp = remember {
    viewModel.calculateTopCoverHeightInDp()
}

Box(modifier = Modifier
    .then(modifier)
    .fillMaxWidth()
    .height(coverImageHeightInDp)
)

And the function in viewModel:

@Composable
fun calculateTopCoverHeightInDp(): Dp {
    val originalImageDimens = Size(1440f, 828f)
    val imageRatio = originalImageDimens.width / originalImageDimens.height
    val configuration = LocalConfiguration.current
    val screenWidthInDp = configuration.screenWidthDp.dp
    return screenWidthInDp / imageRatio
}

How can I code it in a way that the result of this function is remembered and this function is not called again, until screen rotation?

Thanks.

Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
  • why are you doing UI logic in view model? – z.g.y Nov 08 '22 at 08:31
  • I don't want my UI to have any logic. – Bugs Happen Nov 08 '22 at 09:19
  • 1
    I don't think that is an expensive calculation. If it was me I would have put it inside composable. – Emmanuel Mtali Nov 08 '22 at 09:52
  • 1
    If you don't do it inside composable what would happen on configuration change? Device rotation e.t.c – Emmanuel Mtali Nov 08 '22 at 09:56
  • 1
    You generally want to keep "app/data logic" in your viewModel and "UI calculations/work" in the composables themselves, this is an odd way of handling things. – Arthur Kasparian Nov 08 '22 at 09:57
  • @EmmanuelMtali For me, it doesn't matter if it's an expensive calculation or not, it's just redundant. That's why I want to remember it. Also, on device rotation, the same function will be called again, and will return updated value. That's why I'm using `remember` and not `rememberSaveable`. – Bugs Happen Nov 08 '22 at 10:27
  • 1
    @ArthurKasparian Well, you know what they say, you have to be odd to be number 1. :D – Bugs Happen Nov 08 '22 at 10:28
  • I don't get the negative votes. My coding practices aside, isn't my question properly written? Doesn't it not clearly ask what I want to achieve? – Bugs Happen Nov 08 '22 at 10:30
  • @BugsHappen Best of luck to you in that regard! Also, I think the negative votes are because you are using unconventional methods to get a simple outcome, which makes things confusing with no benefit and you stray away from best practices which have been put out by experienced people, I could be wrong though! – Arthur Kasparian Nov 08 '22 at 10:36
  • @ArthurKasparian Thank you! And regarding negative votes, I don't think people should be judged here by their coding style or coding practices. If a question or answer is written with precision, it shouldn't be discouraged. People don't come here to learn about best practices, they come here to get the answers to their questions, even if the answer is a simple "No, it can't be done". – Bugs Happen Nov 08 '22 at 10:48
  • You really think the built-in composables you are using have no logic in them? – Emmanuel Mtali Nov 09 '22 at 14:55
  • @EmmanuelMtali I'm sure they do. It's a matter to preference. I prefer that my composables don't have any logic in them, except for logic (if conditions) to add or not add a specific composable. – Bugs Happen Nov 10 '22 at 05:11

1 Answers1

6

When your computation functions requires some variable from @Composable scope you can just pass the variable you get in composition such as density or configuration

fun calculateTopCoverHeightInDp(configuration: Configuration): Dp {
    val originalImageDimens = Size(1440f, 828f)
    val imageRatio = originalImageDimens.width / originalImageDimens.height
    val screenWidthInDp = configuration.screenWidthDp.dp
    return screenWidthInDp / imageRatio
}

And use it as

val configuration: Configuration = LocalConfiguration.current

val calculatedHeight = remember(configuration){
    calculateTopCoverHeightInDp(configuration)
}

Also you can check out this answer for difference between Composable and non-Composable functions.

What are differents between Composable function and normal function in Android?

Thracian
  • 43,021
  • 16
  • 133
  • 222