Question #388HardNative Android

How does Jetpack Compose's rendering differ from the traditional View system?

#jetpack-compose#rendering#views

Answer

Overview

Compose uses declarative UI with smart recomposition. Views use imperative UI with manual updates.


Comparison

AspectTraditional ViewsJetpack Compose
UI UpdateImperative (manual)Declarative (automatic)
RenderingAndroid CanvasSkia (via Canvas)
LayoutXML + findViewByIdComposable functions
StateManual syncAutomatic recomposition
PerformanceOne-pass measurementMulti-pass

Traditional View System

kotlin
// XML
<TextView android:id="@+id/textView" />

// Code
val textView = findViewById<TextView>(R.id.textView)
textView.text = "Hello" // Manual update
textView.setTextColor(Color.RED)
textView.visibility = View.VISIBLE

Render Pipeline:

  1. Inflate XML → View tree
  2. Measure → Layout → Draw
  3. Manual updates trigger invalidation

Jetpack Compose

kotlin
@Composable
fun MyUI(text: String) {
    Text(
        text = text,
        color = Color.Red,
        modifier = Modifier.fillMaxWidth()
    )
}

Render Pipeline:

  1. Composition → UI tree
  2. Layout → Drawing
  3. State changes → Automatic recomposition

Key Differences

1. State Management

Views

kotlin
class MainActivity : AppCompatActivity() {
    private var count = 0
    private lateinit var textView: TextView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView = findViewById(R.id.textView)
        updateUI() // Manual
    }
    
    fun onButtonClick() {
        count++
        updateUI() // Must call manually
    }
    
    private fun updateUI() {
        textView.text = "Count: $count"
    }
}

Compose

kotlin
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    
    Button(onClick = { count++ }) {
        Text("Count: $count") // Auto-updates
    }
}

2. Recomposition vs Invalidation

Views: Full view hierarchy redrawn

kotlin
textView.text = "New text"
// Triggers: invalidate() → onDraw()

Compose: Only changed composables recompose

kotlin
var text by mutableStateOf("Hello")
Text(text) // Only this Text recomposes

3. No findViewById

Views: Need ID references

kotlin
val button: Button = findViewById(R.id.button)
button.setOnClickListener { }

Compose: Direct references

kotlin
Button(onClick = { }) { Text("Click") }

Performance

Views

  • Mature, highly optimized
  • Single-pass layout
  • Better for complex animations

Compose

  • Smart recomposition (skips unchanged)
  • Declarative = less code
  • Better for reactive UI

Bottom Line: Compose trades some performance for massive productivity gains and simpler code.