Android: Use ComposeView with RecyclerView

Aman Shandilya
4 min readAug 9, 2024

--

Photo by Clay Banks on Unsplash

RecyclerView is a powerful and flexible UI component in Android development which is used to display large datasets efficiently. Almost in every Android application development we use it. We can mold it as per our need e.g. to display different type of views in terms of height, width and working. It has efficient mechanism to recycle the views, animating the views and has adapter which act as bridge between your data and RecyclerView.

Since Jetpack Compose is introduced it is gaining popularity in a much faster pace. Jetpack Compose is a modern UI toolkit available and i hope you all must be learning and implementing it in your current projects.

Unlike the traditional imperative approach with XML layouts, Compose allows you to describe your UI by calling composable functions that take data and emit UI elements. In this blog we will try to use Jetpack Compose with RecyclerView. This can help you to migrate old android application to Jetpack Compose without changing the code completely.

We will create a RecyclerView which will inflate traditional UI component and UI component from Jetpack UI toolkit together.

Assuming we have all the required dependency added for Jetpack and other components.

First we will create an Activity class.
While seeing below Activity class code we can easily understand that we are creating RecyclerView and attaching Adapter with this to display the data.

class ComposeInNativeViewActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val activityComposeBinding =
DataBindingUtil.setContentView<ActivityComposeBinding>(this, R.layout.activity_compose)

val adapter = ActivityComposeAdapter()

activityComposeBinding.recyclerView.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)

activityComposeBinding.recyclerView.adapter = adapter
}

}

Now create xml file activity_compose.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="16dp"/>

</LinearLayout>
</layout>

Now we will create the adapter and in the adapter we will inflate two different view items. One is to use traditionally available UI component and another is to use ComposeView from Jetpack Compose UI toolkit.

ComposeView is a bridge that allows you to embed Jetpack Compose UI elements within your existing traditional Android views and layouts. It acts as a container for Compose content, enabling you to gradually adopt Compose in your app without rewriting everything at once. This will help us to combine traditional views and Compose elements in the same layout.

So now will create two different xml files as explained above.
1. item_native.xml
2. item_compose.xml

Create item_native.xml file.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Native View Item"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold" />

</layout>

Create item_compose.xml file.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</layout>

Now we will use both xml files in our Adapter class and will combine traditional views and Compose elements in the same layout.

Create Adapter class for RecyclerView

class ActivityComposeAdapter() : RecyclerView.Adapter<MyViewHolder>() {


class MyViewHolder(val viewDataBinding: ViewDataBinding) :
RecyclerView.ViewHolder(viewDataBinding.root) {

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = when (viewType) {
1 -> {
DataBindingUtil.inflate<ItemNativeBinding>(
LayoutInflater.from(parent.context),
R.layout.item_native,
parent,
false
)
}

else -> {
DataBindingUtil.inflate<ItemComposeBinding>(
LayoutInflater.from(parent.context),
R.layout.item_compose,
parent,
false
)
}
}
return MyViewHolder(view)
}

override fun getItemCount(): Int {
return 30
}

override fun getItemViewType(position: Int): Int {
val pos = position % 2
return when (pos) {
0 -> 1
else -> 2
}
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) =
when (getItemViewType(position)) {
1 -> {
val binding = holder.viewDataBinding as ItemNativeBinding
binding.textView.setText("Native view inflated")
}

else -> {
val binding = holder.viewDataBinding as ItemComposeBinding
binding.composeView.setContent {
Text(
modifier = Modifier.padding(top = 16.dp),
text = "Compose view inflated",
style = TextStyle(fontSize = 20.sp, fontWeight = FontWeight.Bold)
)
}
}
}
}

As you can see in the above Adapter class how in the onCreateViewHolder() method we are using the item_compose.xml file which contains the ComposeView from Jetpack Compose UI toolkit while utilizing the same traditional way of create the RecyclerView. And in the onBindViewHolder() see how we are using ComposeView to add Jetpack Compose UI element in it.

Conclusion:
With above approach we can gradually move to Jetpack Compose without changing most of the code. As we know that Jetpack Compose requires less code than traditional XML layouts which makes code easier to understand and maintain.

Thanks for reading.
Happy Coading :)

--

--

Aman Shandilya

Never be serious by Nature, Always be serious for Nature.