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

MaterialShapeDrawable caused OOM

Aperta
#4,128 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug Need more info
Lingua principale
Java
Stelle
17.4k
Fork
3.2k
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Description: OOM with RecyclerView with MaterialCardView.

Expected behavior: No OOM

Source code:

XML layout

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_margin="@dimen/space_2"
    app:cardCornerRadius="5dp">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/postImage"
                android:layout_width="match_parent"
                android:layout_height="120dp"
                android:adjustViewBounds="true"
                android:src="@drawable/logo_placeholder"
                android:background="@color/colorWhiteDark_Primary" />

            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="@dimen/space_8">

                <com.google.android.material.textview.MaterialTextView
                    android:id="@+id/postTitle"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingBottom="@dimen/space_4"
                    android:textColor="@color/colorPrimaryDark_Accent"
                    android:textSize="@dimen/textSize16"
                    android:maxLines="2"
                    android:textStyle="bold"
                    android:ellipsize="end"
                    tools:text="@tools:sample/full_names" />

                <com.google.android.material.textview.MaterialTextView
                    android:id="@+id/postTime"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:ellipsize="end"
                    android:maxLines="1"
                    android:textSize="@dimen/textSize12"
                    tools:text="@tools:sample/cities"/>

                <com.google.android.material.textview.MaterialTextView
                    android:id="@+id/postDescription"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textSize="@dimen/textSize12"
                    android:maxLines="2"
                    android:ellipsize="end"
                    android:paddingVertical="@dimen/space_4"
                    tools:text="@tools:sample/lorem/random" />

            </androidx.appcompat.widget.LinearLayoutCompat>

        </androidx.appcompat.widget.LinearLayoutCompat>

</com.google.android.material.card.MaterialCardView>

RecyclerView Adapter

class HorizontalNewsAdapter(
    private val glide: RequestManager,
    private val itemListener: ItemListener
) : FilterableListAdapter<WordPressPostDataDomain, HorizontalNewsAdapter.ItemView>(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<Any>) {

        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<WordPressPostDataDomain>, constraint: String): List<WordPressPostDataDomain> {
        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.<init>(MaterialShapeDrawable.java:126)
05:47:18.338  W    at com.google.android.material.shape.MaterialShapeDrawable.<init>(MaterialShapeDrawable.java:222)
05:47:18.338  W    at com.google.android.material.shape.MaterialShapeDrawable.<init>(MaterialShapeDrawable.java:213)
05:47:18.338  W    at com.google.android.material.card.MaterialCardViewHelper.<init>(MaterialCardViewHelper.java:143)
05:47:18.338  W    at com.google.android.material.card.MaterialCardView.<init>(MaterialCardView.java:174)
05:47:18.338  W    at com.google.android.material.card.MaterialCardView.<init>(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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con l’XML fornito e lo stack trace in MaterialShapeDrawable.java:126, quindi segui la costruzione attraverso MaterialCardViewHelper.java e MaterialCardView.java. Riproduci il percorso di inflazione di RecyclerView da HorizontalNewsAdapter.kt:98 e determina se l’OOM segnalato è causato dal codice di Material Components o dal layout di esempio. Il lavoro è completato quando sono disponibili una causa riproducibile e una risoluzione verificata oppure una diagnosi chiara di upstream.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
java
Ambito
mobile-dev
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Da chiarire
Idoneità per principianti
25/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.