Makuhari Development Corporation
5 min read, 878 words, last updated: 2025/11/14
TwitterLinkedInFacebookEmail

AGP 8.10 to 8.13 Upgrade: Debugging Compose Dialog Rendering Issues

When upgrading Android Gradle Plugin (AGP) from 8.10.0 to 8.13.0, developers occasionally encounter unexpected UI behaviors, including dialogs rendering multiple times. While these patch version upgrades shouldn't introduce breaking changes, certain implementation patterns can trigger indirect effects on UI components.

The Problem

After upgrading AGP from 8.10.0 to 8.13.0, some applications experience:

  • Dialogs appearing multiple times
  • UI components re-rendering unexpectedly
  • Compose recomposition storms
  • Fragment lifecycle issues

The question arises: Is the AGP upgrade directly causing these issues, and what's the probability of such occurrences?

Investigation

Understanding the AGP 8.10 → 8.13 Changes

AGP 8.10.0 to 8.13.0 represents a patch-level upgrade within the same minor version series. According to official release notes, these versions primarily contain:

  • R8/D8 optimizer improvements: Enhanced tree-shaking and dex compilation
  • Gradle task scheduler updates: Better incremental build performance
  • Compose Compiler integration adjustments: Automatic version alignment mechanisms

Identifying Compose Compiler Version

Since kotlinCompilerExtensionVersion isn't showing up in your project, here's how to check your Compose Compiler version:

Method 1: Check build.gradle (Module level)

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.15" // This line might be missing
    }
}

Method 2: Check Compose BOM version

dependencies {
    implementation(platform("androidx.compose:compose-bom:2024.06.00"))
    // The BOM determines Compose Compiler version
}

Method 3: Gradle dependency report

./gradlew :app:dependencies --configuration debugCompileClasspath | grep compose-compiler

Method 4: Build scan analysis

// Add to build.gradle
tasks.register("printComposeCompilerVersion") {
    doLast {
        configurations.forEach { config ->
            config.resolvedConfiguration.resolvedArtifacts.forEach { artifact ->
                if (artifact.name.contains("compose-compiler")) {
                    println("Compose Compiler: ${artifact.moduleVersion}")
                }
            }
        }
    }
}

Root Cause Analysis

Potential Triggers for Dialog Re-rendering

Cause Mechanism Probability
Compose Compiler Mismatch AGP 8.13 enforces stricter version alignment between Kotlin and Compose Compiler ★★★☆☆ (Medium)
R8 Optimization Changes Aggressive lambda inlining affects anonymous class lifecycles in dialog controllers ★★☆☆☆ (Low)
ViewBinding/DataBinding Cache Resource merge cache key algorithm updates cause binding regeneration ★☆☆☆☆ (Very Low)

Debugging the Issue

  1. Check for Compose Recomposition Storms
@Composable
fun MyDialog() {
    // Add logging to detect excessive recompositions
    LaunchedEffect(Unit) {
        Log.d("Recomposition", "Dialog recomposed at ${System.currentTimeMillis()}")
    }
    
    // Ensure proper state management
    var showDialog by remember { mutableStateOf(false) }
    
    // ❌ Wrong: This causes recomposition storm
    // if (someCondition) showDialog = true
    
    // ✅ Correct: Use LaunchedEffect for side effects
    LaunchedEffect(someCondition) {
        if (someCondition) {
            showDialog = true
        }
    }
}
  1. Verify Kotlin/Compose Compatibility
// Check current versions in build.gradle
kotlin {
    jvmToolchain(17)
}
 
compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}
 
composeOptions {
    // Ensure compatibility matrix
    kotlinCompilerExtensionVersion = "1.5.15" // For Kotlin 1.9.25
}

Solution

Step 1: Lock Compose Compiler Version

android {
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.15"
    }
}
 
// In gradle.properties
android.compose.compiler.reportMetrics=false

Step 2: Validate R8 Configuration

If using ProGuard/R8, temporarily disable aggressive optimizations:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            // Add temporarily to test
            // -dontoptimize
        }
    }
}

Step 3: Fix Common Dialog Re-rendering Patterns

Compose Dialog Pattern

@Composable
fun ProperDialogHandling() {
    var showDialog by remember { mutableStateOf(false) }
    
    // ✅ Correct: Single source of truth
    LaunchedEffect(triggerCondition) {
        if (triggerCondition && !showDialog) {
            showDialog = true
        }
    }
    
    if (showDialog) {
        AlertDialog(
            onDismissRequest = { showDialog = false },
            title = { Text("Dialog") },
            confirmButton = {
                TextButton(onClick = { showDialog = false }) {
                    Text("OK")
                }
            }
        )
    }
}

Fragment Dialog Pattern

class MyFragment : Fragment() {
    private var dialogShown = false
    
    override fun onResume() {
        super.onResume()
        // ❌ Wrong: May trigger multiple times
        // if (shouldShowDialog) showDialog()
        
        // ✅ Correct: Guard against multiple calls
        if (shouldShowDialog && !dialogShown) {
            showDialog()
            dialogShown = true
        }
    }
    
    private fun showDialog() {
        if (!isAdded || isDetached) return
        
        MyDialogFragment().apply {
            setTargetFragment(this@MyFragment, 0)
            show(parentFragmentManager, "dialog")
        }
    }
}

Step 4: Update Gradle Properties

# gradle.properties
org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.caching=true
 
# Kotlin optimizations
kotlin.incremental=true
kotlin.incremental.useClasspathSnapshot=true

Lessons Learned

Prevention Tips

  1. Version Alignment is Critical: Always ensure Kotlin compiler version matches Compose compiler version according to the compatibility map.

  2. State Management Best Practices: Use remember, LaunchedEffect, and proper lifecycle-aware components to prevent UI re-rendering.

  3. Gradual Upgrades: Test AGP upgrades in isolation before combining with other dependency updates.

  4. Build Configuration Validation: After AGP upgrades, verify that R8/ProGuard rules haven't inadvertently changed optimization behavior.

Key Takeaways

  • AGP 8.10 → 8.13 upgrade probability of causing dialog re-rendering: <5%
  • Most UI issues stem from Compose Compiler version mismatches or improper state management
  • R8 optimization changes can occasionally affect anonymous class lifecycles
  • Always test release builds separately as R8 behavior differs from debug builds

Monitoring and Detection

Set up proper logging to catch recomposition issues early:

// Compose debugging
@Composable
fun <T> T.logCompositions(tag: String): T {
    if (BuildConfig.DEBUG) {
        Log.d("Recomposition", "$tag: Composition")
    }
    return this
}

By following these debugging steps and prevention strategies, you can confidently upgrade AGP while maintaining stable UI behavior across your Android application.

Makuhari Development Corporation
法人番号: 6040001134259
サイトマップ
ご利用にあたって
個人情報保護方針
個人情報取扱に関する同意事項
お問い合わせ
Copyright© Makuhari Development Corporation. All Rights Reserved.