I prefer using a Spacer to add some padding between views, sometimes you could just add this space as padding to the views. So my question is are there any performance drawbacks of using Spacers versus using the good old padding values?
The performance will vary. In the test below, 50 items are rendered with padding followed by 50 items using spacers. The spacers render around twice as fast. But if you reverse the order and render 50 items with spacers first followed by 50 items with padding, the padding is faster with around 0.2 times the duration it takes with spacers. So clearly the number of items and the order in which they are rendered is going to affect the performance significantly. I suspect someone at Google gives you better performance if you like cats more than you like dogs :-)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startActivity(intent)
setContent {
val modifierPadding = Modifier.padding(bottom = 10.dp)
val modifierSpacer = Modifier
.requiredHeight(1.dp)
.fillMaxWidth()
Column(modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())) {
val startTimePadding = System.nanoTime()
repeat(50) {
Text("I like dogs", modifier = modifierPadding)
}
val durationPadding = System.nanoTime() - startTimePadding
val startTimeSpacer = System.nanoTime()
repeat(50) {
Text("I like cats")
Spacer(modifier = modifierSpacer)
}
val durationSpacer = System.nanoTime() - startTimeSpacer
Text("padding to spacer ratio: " + (durationPadding.toFloat() / durationSpacer.toFloat()))
}
}
}
}
I believe the accepted answer has multiple flaws:
Here is my crack for an experiment. I am using a Samsung Galaxy A23. To help create a predictable environment, I restarted the device, put it in airplane mode and let it sit for a bit. The most important aspect is that I ensured the test application is running a release build. Testing performance in a debug build is always a waste of time. I created a matrix of 45 by 70 (3150) Text Composables consisting only of a period ('.'). I spaced these periods with an end padding of 1dp or with an end Spacer of width 1dp. The app starts by drawing nothing. When I click a button it draws the matrix of periods with padding. When I click again, it draws the matrix using Spacers. I ran this test 10 times with Spacers and 10 times with padding.
My code is the following:
package com.packagename.spacervspadding
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
class MainActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SpacerVsPadding()
}
}
}
const val HEIGHT = 45
const val WIDTH = 70
@Composable
fun SpacerVsPadding() {
var showContent by remember { mutableStateOf<Boolean?>(null) }
val paddingModifier = Modifier.padding(end = 1.dp)
val spacerModifier = Modifier.width(1.dp)
showContent?.let { padding ->
if(padding) {
val startNs = System.nanoTime()
Column {
repeat(HEIGHT) {
Row {
repeat(WIDTH) {
Text(text = ".", modifier = paddingModifier)
}
}
}
}
val paddingTimeNs = System.nanoTime() - startNs
Log.d("SpacerVsPadding", "Padding: Total - ${paddingTimeNs}ns")
} else {
val startNs = System.nanoTime()
Column {
repeat(HEIGHT) {
Row {
repeat(WIDTH) {
Text(text = ".")
Spacer(modifier = spacerModifier)
}
}
}
}
val spacerTimeNs = System.nanoTime() - startNs
Log.d("SpacerVsPadding", "Spacer: Total - ${spacerTimeNs}ns")
}
}
Box(modifier = Modifier.fillMaxSize()){
FloatingActionButton(
onClick = { showContent = if(showContent == false) true else false },
modifier = Modifier.align(Alignment.BottomEnd)
){
Icon(imageVector = Icons.Outlined.Refresh, contentDescription = "Refresh Icon")
}
}
}
@Preview
@Composable
fun PreviewSpacerVsPadding() = SpacerVsPadding()
Code can also be viewed as a GitHub Gist.
And here is a screenshot of the test app.
Here is the output I received after pressing the refresh button 20 times (10 tests each for padding & Spacer). Nanosecond samples from rendering 3,150 periods ('.') with 1dp spacing:
Spacer: 38,240,990ns
Spacer: 40,810,833ns
Spacer: 34,016,823ns
Spacer: 33,982,240ns
Spacer: 33,358,282ns
Spacer: 33,909,010ns
Spacer: 32,837,188ns
Spacer: 33,117,344ns
Spacer: 32,885,365ns
Spacer: 32,316,198ns
Padding: 21,938,282ns
Padding: 20,541,250ns
Padding: 19,936,511ns
Padding: 20,342,604ns
Padding: 20,024,844ns
Padding: 19,291,875ns
Padding: 19,519,323ns
Padding: 19,195,677ns
Padding: 19,712,032ns
Padding: 19,537,135ns
Adding these times together, the total time of rendering 45 x 70 x 10 or 31,500 periods ('.') follow by a 1dp space:
Spacer: 345,474,273ns
Padding: 200,039,533ns
And the average nanoseconds per period ('.') followed by a 1dp space:
Spacer: 10,967ns
Padding: 6,350ns
Although the test is not perfect (it doesn't take into consideration the possibility of a large number of @Composables running on a separate thread from the calls to System.nanotime(), for example), the measurements certainly do tell a convincing story. From this data, I am confident that a @Composable with padding is almost twice as fast as using a single Spacer to achieve the same effect. This can only be more true for a padding that achieves same effect of multiple Spacers. However, this is strictly a conclusion of performance and says nothing about other potential benefits of padding over Spacers or vice versa.
Compose version tested: 1.6.6
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With