material-components / material-components/material-components-android

MaterialShapeDrawable caused OOM

Open
#4,128 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Need more info
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.