material-components / material-components/material-components-android
MaterialShapeDrawable caused OOM
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 17.4k
- Forks
- 3.2k
- PR merge metrics
- No merged PRs in 30d
Description
**Description:** OOM with RecyclerView with MaterialCardView.
**Expected behavior:** No OOM
**Source code:**
**XML layout**
```
```
**RecyclerView Adapter**
```
class HorizontalNewsAdapter(
private val glide: RequestManager,
private val itemListener: ItemListener
) : FilterableListAdapter(DiffUtilNews()) {
inner class ItemView(itemView: TrendingCardBinding) : RecyclerView.ViewHolder(itemView.root) {
private val titleTxtV: MaterialTextView = itemView.postTitle
private val dateTxtV: MaterialTextView = itemView.postTime
private val descriptionTxtV: MaterialTextView = itemView.postDescription
private val featuredImage: AppCompatImageView = itemView.postImage
// Full update/binding
fun bindFull(domain: WordPressPostDataDomain) {
with(domain) {
bindTextData(titleDomain.formattedTitle, formattedDate, contentDomain.strippedImageTagContent)
glide
.load(featuredMediaUrl)
.placeholder(itemView.context.resToDrawable(R.drawable.logo_placeholder))
.centerCrop()
.into(featuredImage)
// It is advisable to always use interface when working with `setOnClickListener`
// in adapter to avoid outdated binding and data reference.
// Passing position and using `adapter.currentList[position]` in the Activity/Fragment
// is better than declaring `getItem(position)` inside `setOnClickListener`
// Reference: https://stackoverflow.com/q/77308368/12204620
itemView.setOnClickListener {
itemListener.onItemSelected(bindingAdapterPosition)
}
}
}
// Partial update/binding
fun bindPartial(bundle: Bundle) {
bindTextData(
bundle.getString(DiffUtilNews.ARG_NEWS_TITLE),
bundle.getString(DiffUtilNews.ARG_NEWS_DATE),
bundle.getString(DiffUtilNews.ARG_NEWS_STRIPPED_CONTENT)
)
}
private fun bindTextData(title: String?, date: String?, description: String?) {
titleTxtV.text = title
dateTxtV.text = date
descriptionTxtV.text = description
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemView {
return ItemView(
TrendingCardBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
override fun onBindViewHolder(holder: ItemView, position: Int) {
// Reference: https://forums.raywenderlich.com/t/speed-up-your-android-recyclerview-using-diffutil-raywenderlich-com/141338/8?u=archeremiya
onBindViewHolder(holder, holder.bindingAdapterPosition, emptyList())
}
override fun onBindViewHolder(holder: ItemView, position: Int, payloads: List) {
holder.apply {
// For most cases `getBindingAdapterPosition()` is use as it provides the most up-to-date position considering pending changes.
// It is also ideal for getting data from `getCurrentList()` as it returns the only position under this specific adapter and
// not the entire adapters of a ConcatAdapter.
// Reference: https://stackoverflow.com/a/63148812
val domain = getItem(bindingAdapterPosition)
if (payloads.isEmpty() || payloads.first() !is Bundle) {
holder.bindFull(domain) // Full update/binding
}
else {
val bundle = payloads.first() as Bundle
holder.bindPartial(bundle) // Partial update/binding
}
}
}
// Required when setHasStableIds is set to true
override fun getItemId(position: Int): Long {
return currentList[position].id.toLong()
}
override fun onFilter(list: List, constraint: String): List {
TODO("Not yet implemented")
}
fun interface ItemListener {
fun onItemSelected(position: Int)
}
}
```
**OOM**
```
05:47:18.336 W Throwing OutOfMemoryError "Failed to allocate a 28 byte allocation with 3984 free bytes and 3KB until OOM" (recursive case)
05:47:18.338 W "main" prio=5 tid=1 Runnable
05:47:18.338 W | group="main" sCount=0 dsCount=0 obj=0x73c04710 self=0x7bce33ba00
05:47:18.338 W | sysTid=3946 nice=-6 cgrp=default sched=0/0 handle=0x7bd184ffe8
05:47:18.338 W | state=R schedstat=( 2083268596 213661445 6688 ) utm=183 stm=25 core=2 HZ=100
05:47:18.338 W | stack=0x7fd8420000-0x7fd8422000 stackSize=8MB
05:47:18.338 W | held mutexes= "mutator lock"(shared held)
05:47:18.338 W at com.google.android.material.shape.MaterialShapeDrawable.(MaterialShapeDrawable.java:126)
05:47:18.338 W at com.google.android.material.shape.MaterialShapeDrawable.(MaterialShapeDrawable.java:222)
05:47:18.338 W at com.google.android.material.shape.MaterialShapeDrawable.(MaterialShapeDrawable.java:213)
05:47:18.338 W at com.google.android.material.card.MaterialCardViewHelper.(MaterialCardViewHelper.java:143)
05:47:18.338 W at com.google.android.material.card.MaterialCardView.(MaterialCardView.java:174)
05:47:18.338 W at com.google.android.material.card.MaterialCardView.(MaterialCardView.java:160)
05:47:18.338 W at java.lang.reflect.Constructor.newInstance!(Native method)
05:47:18.338 W at android.view.LayoutInflater.createView(LayoutInflater.java:619)
05:47:18.338 W at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:764)
05:47:18.338 W at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
05:47:18.338 W at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
05:47:18.338 W at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
05:47:18.338 W at com.sample.app.databinding.TrendingCardBinding.inflate(TrendingCardBinding.java:59)
05:47:18.338 W at com.sample.app.presentation.adapters.HorizontalNewsAdapter.onCreateViewHolder(HorizontalNewsAdapter.kt:98)
05:47:18.338 W at com.sample.app.presentation.adapters.HorizontalNewsAdapter.onCreateViewHolder(HorizontalNewsAdapter.kt:40)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7788)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6873)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6757)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6753)
05:47:18.338 W at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2362)
05:47:18.338 W at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1662)
05:47:18.338 W at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1622)
05:47:18.338 W at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:687)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4645)
05:47:18.338 W at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:4022)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.measureChildBeforeLayout(LinearLayoutCompat.java:1401)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.measureVertical(LinearLayoutCompat.java:685)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.onMeasure(LinearLayoutCompat.java:575)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.measureChildBeforeLayout(LinearLayoutCompat.java:1401)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.measureVertical(LinearLayoutCompat.java:685)
05:47:18.338 W at androidx.appcompat.widget.LinearLayoutCompat.onMeasure(LinearLayoutCompat.java:575)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at androidx.core.widget.NestedScrollView.measureChildWithMargins(NestedScrollView.java:1921)
05:47:18.338 W at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
05:47:18.338 W at androidx.core.widget.NestedScrollView.onMeasure(NestedScrollView.java:640)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:760)
05:47:18.338 W at com.google.android.material.appbar.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:100)
05:47:18.338 W at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:2348)
05:47:18.338 W at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:831)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
05:47:18.338 W at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:145)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
05:47:18.338 W at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
05:47:18.338 W at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
05:47:18.338 W at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
05:47:18.338 W at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
05:47:18.338 W at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
05:47:18.338 W at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
05:47:18.338 W at android.view.View.measure(View.java:18788)
05:47:18.338 W at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
05:47:18.338 W at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
05:47:18.338 W at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
05:47:18.338 W at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
05:47:18.338 W at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
05:47:18.338 W at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
05:47:18.338 W at android.view.Choreographer.doCallbacks(Choreographer.java:670)
05:47:18.338 W at android.view.Choreographer.doFrame(Choreographer.java:606)
05:47:18.338 W at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
05:47:18.338 W at android.os.Handler.handleCallback(Handler.java:739)
05:47:18.338 W at android.os.Handler.dispatchMessage(Handler.java:95)
05:47:18.338 W at android.os.Looper.loop(Looper.java:148)
05:47:18.338 W at android.app.ActivityThread.main(ActivityThread.java:5417)
05:47:18.338 W at java.lang.reflect.Method.invoke!(Native method)
05:47:18.338 W at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
05:47:18.338 W at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
05:47:18.338 W
```
**Minimal sample app repro:** N/A
**Android API version:** N/A
**Material Library version:** N/A (Sorry can't remember when this crash due to OOM happen, I kept this log long ago to submit a report but forgot to do so but surely before or during v1.10.0)
**Device:** N/A
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the supplied XML and the stack trace at MaterialShapeDrawable.java:126, then follow construction through MaterialCardViewHelper.java and MaterialCardView.java. Reproduce the RecyclerView inflation path from HorizontalNewsAdapter.kt:98 and determine whether the reported OOM is caused by the Material Components code or the sample layout. Done means a reproducible cause and a verified resolution or clear upstream diagnosis.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100