Embedding Jetpack Compose in RecyclerView with ComposeView and Dispose Strategies
This article explains how to embed Jetpack Compose within an existing RecyclerView using ComposeView, examines the default DisposeOnDetachedFromWindow strategy, its impact on view recycling, and presents alternative composition strategies such as DisposeOnViewTreeLifecycleDestroyed and the newer pooling-aware strategy to improve performance.
Background & Author's Note: The author introduces the growing popularity of Jetpack Compose and the desire to migrate existing View‑based projects to Compose using ComposeView , while warning about hidden performance costs.
Integrating Compose into the Existing View System: In a pure Compose project setContent { … } replaces setContentView . When adding Compose to a traditional View hierarchy, ComponentActivity.setContent creates a ComposeView and inserts it into android.R.id.content . The author demonstrates a simple activity that inflates a layout containing a RecyclerView and then creates a ComposeView for each item in the adapter.
class CustomActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom)
val recyclerView = findViewById
(R.id.recyclerView)
recyclerView.adapter = MyRecyclerViewAdapter()
recyclerView.layoutManager = LinearLayoutManager(this)
}
}
class MyRecyclerViewAdapter : RecyclerView.Adapter
() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyComposeViewHolder {
val view = ComposeView(parent.context)
return MyComposeViewHolder(view)
}
override fun onBindViewHolder(holder: MyComposeViewHolder, position: Int) {
holder.composeView.setContent {
Text(text = "test $position", modifier = Modifier.size(200.dp).padding(20.dp), textAlign = TextAlign.Center)
}
}
override fun getItemCount() = 200
}
class MyComposeViewHolder(val composeView: ComposeView) : RecyclerView.ViewHolder(composeView)Exploring Compose: The article briefly mentions Compose’s recomposition process and focuses on when a composition is disposed. The default strategy in Compose 1.1.1 is ViewCompositionStrategy.DisposeOnDetachedFromWindow , which adds an OnAttachStateChangeListener that calls view.disposeComposition() when the view is detached.
private var disposeViewCompositionStrategy: (() -> Unit)? =
ViewCompositionStrategy.DisposeOnDetachedFromWindow.installFor(this)The disposal implementation clears the composition, removes slots, and notifies the composer.
fun disposeComposition() {
composition?.dispose()
composition = null
requestLayout()
}Conflict with RecyclerView: Because RecyclerView recycles its ViewHolders, a ComposeView that has been disposed would no longer participate in recomposition. However, the setContent method recreates the composition if it is null, so recycled holders still work correctly.
fun setContent(content: @Composable () -> Unit) {
shouldCreateCompositionOnAttachedToWindow = true
this.content.value = content
if (isAttachedToWindow) {
createComposition()
}
}Other Dispose Strategies: The author introduces DisposeOnViewTreeLifecycleDestroyed , which disposes the composition only when the associated lifecycle reaches ON_DESTROY . This is set in the ViewHolder’s init block.
class MyComposeViewHolder(val composeView: ComposeView) : RecyclerView.ViewHolder(composeView) {
init {
composeView.setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
}
}Extension – New Default Strategy: Starting with Compose 1.3.0‑alpha02, the default strategy became DisposeOnDetachedFromWindowOrReleasedFromPool , which also checks view.isWithinPoolingContainer to avoid disposing views that are being pooled by RecyclerView. This reduces the hidden performance overhead when using Compose inside recyclable containers.
Conclusion: Compose offers significant architectural and performance benefits over the traditional View system, but developers must understand composition disposal strategies, especially when integrating with RecyclerView, to avoid unnecessary memory churn. The article encourages developers to adopt Compose and experiment with the newer pooling‑aware strategy.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.