agentsclimarketplace

Android performance

Skill thetruong1099/android-mvi-base-code/.claude/skills/android-performance

Install
npx -y skills add thetruong1099/android-mvi-base-code --skill android-performance

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Android performance best practices for this project. Covers Compose stability and recomposition reduction, LazyList optimization with stable keys and contentType, image loading with Coil, Paging3 caching with cachedIn, memory management avoiding Context in ViewModels, and ProGuard rules for Moshi and Konvert.

SKILL.md

3.0 KB, as published. Nobody here has run it

Android Performance

Compose Performance

Stability & Recomposition

// Mark classes as @Immutable when passed to Composable
@Immutable
data class ItemUiModel(val id: String, val name: String, val coverUrl: String)

// Lambda parameters are stable - prefer over direct ViewModel access
@Composable fun ItemCard(onItemClick: () -> Unit)           // GOOD: stable
@Composable fun ItemCard(viewModel: SampleViewModel)        // BAD: unstable

remember & derivedStateOf

val sortedItems = remember(items) { items.sortedBy { it.name } }  // cache expensive computation
val hasItems by remember { derivedStateOf { items.isNotEmpty() } }  // derived from other state

LazyList Performance

// Always provide stable keys
LazyColumn {
    items(items, key = { it.id }) { item -> ItemComponent(item) }
}

// contentType for heterogeneous lists
LazyColumn {
    items(items, key = { it.id }, contentType = { it.type }) { item ->
        when (item) {
            is Header -> HeaderComponent(item)
            is Item   -> ItemComponent(item)
        }
    }
}

Image Loading (Coil)

AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data(item.imageUrl)
        .crossfade(true)
        .build(),
    contentDescription = item.name,
    modifier = Modifier.size(120.dp, 160.dp),
)

Paging Performance

// ALWAYS cachedIn(viewModelScope) to survive configuration changes
val result = callPagingDataWithInternet(
    callFlow = { useCase() },
    onError = { showErrorToast(it) },
).cachedIn(viewModelScope)  // Essential!

// PagingConfig tuning
PagingConfig(
    pageSize = 20,
    prefetchDistance = 5,         // How far ahead to prefetch
    enablePlaceholders = false,   // false for network-only
    initialLoadSize = 40,         // First page size
)

Memory Management

// WRONG: Context in ViewModel = memory leak
class MyViewModel(private val context: Context)

// RIGHT: ApplicationContext via Hilt
@HiltViewModel
class MyViewModel @Inject constructor(
    @ApplicationContext private val appContext: Context
) : BaseViewModel<...>()

// Collect flows lifecycle-aware
val state by viewModel.uiState.collectAsStateWithLifecycle()

Network Performance

OkHttpClient.Builder()
    .cache(Cache(cacheDir, 10 * 1024 * 1024))  // 10MB cache
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build()

ProGuard/R8 Rules

# Moshi
-keep class com.template.data.**.dto.** { *; }
-keepclassmembers class * { @com.squareup.moshi.Json <fields>; }

# Konvert generated mappers
-keep class com.template.data.**.mapper.** { *; }

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.