android - AppCompatButton 上的内存泄漏

标签 android android-layout android-fragments performance-testing leakcanary

我正在开发一个集成了 LeakCanary 的应用程序。在我的整个应用程序中,我不断收到 LeakCanary 通知“应用程序将卡住,Brrr ...”。现在,如果泄漏是一致的,则不能忽略。所以我浏览了日志并在下面找到了。

├─ com.ilumi.fragments.ListFragment
│    Leaking: YES (Fragment#mFragmentManager is null)
│    ↓ ListFragment.mAddToList
├─ com.ilumi.widgets.CenteredLeftDrawableButton
│    Leaking: YES (ListFragment↑ is leaking and View.mContext references a destroyed activity)
│    mContext instance of com.ilumi.activities.DetailActivity with mDestroyed = true
│    View#mParent is set
│    View#mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 1
│    ↓ CenteredLeftDrawableButton.mContext
╰→ com.ilumi.activities.DetailActivity
 ​     Leaking: YES (CenteredLeftDrawableButton↑ is leaking and Activity#mDestroyed is true and 

现在从它的外观来看,我认为问题出在我在我的应用程序的许多地方使用过的 CenteredLeftDrawableButton 上。

public class CenteredLeftDrawableButton extends AppCompatButton {

    public CenteredLeftDrawableButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CenteredLeftDrawableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CenteredLeftDrawableButton(Context context) {
        super(context);
    }

    @Override
    public void setCompoundDrawablePadding(int pad) {
        super.setCompoundDrawablePadding(pad);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
        super.setCompoundDrawables(left, top, right, bottom);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end, int bottom) {
        super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top, Drawable end, Drawable bottom) {
        super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) {
        super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
        super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
        centerDrawables();
    }

    @Override
    public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end, Drawable bottom) {
        super.setCompoundDrawablesRelative(start, top, end, bottom);
        centerDrawables();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        centerDrawables();
    }

    private void centerDrawables() {
        Drawable[] compoundDrawables = getCompoundDrawables();
        Drawable drawableLeft = compoundDrawables[0];
        Drawable drawableRight = compoundDrawables[2];
        if (drawableLeft != null || drawableRight != null) {
            float textWidth = getPaint().measureText(getText().toString());
            int drawablePadding = getCompoundDrawablePadding();
            int drawableWidth = 0;
            if (drawableLeft != null) {
                drawableWidth += drawableLeft.getIntrinsicWidth();
            }
            if (drawableRight != null) {
                drawableWidth += drawableRight.getIntrinsicWidth();
            }
            float bodyWidth = textWidth + drawableWidth + drawablePadding;
            if (bodyWidth < getWidth()) {
                float emptySpace = getWidth() - bodyWidth;
                int paddingToLeftAndRight = (int) (emptySpace / 2);
                setPadding(paddingToLeftAndRight, getPaddingTop(), paddingToLeftAndRight, getPaddingBottom());
            }
        }
    }

    public static void centerDrawables(TextView view) {
        Drawable[] compoundDrawables = view.getCompoundDrawables();
        Drawable drawableLeft = compoundDrawables[0];
        Drawable drawableRight = compoundDrawables[2];
        if (drawableLeft != null || drawableRight != null) {
            float textWidth = view.getPaint().measureText(view.getText().toString());
            int drawablePadding = view.getCompoundDrawablePadding();
            int drawableWidth = 0;
            if (drawableLeft != null) {
                drawableWidth += drawableLeft.getIntrinsicWidth();
            }
            if (drawableRight != null) {
                drawableWidth += drawableRight.getIntrinsicWidth();
            }
            float bodyWidth = textWidth + drawableWidth + drawablePadding;
            if (bodyWidth < view.getWidth()) {
                float emptySpace = view.getWidth() - bodyWidth;
                int paddingToLeftAndRight = (int) (emptySpace / 2);
                view.setPadding(paddingToLeftAndRight, view.getPaddingTop(), paddingToLeftAndRight, view.getPaddingBottom());
            }
        }
    }
}

我下面的每个类都是我正在做的按钮的使用。

      private CenteredLeftDrawableButton mAddToSchedule;


@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    mAddToSchedule = (CenteredLeftDrawableButton) view.findViewById(R.id.editScheduleButton);

mAddToSchedule.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Intent to open new screen
            }
        });
    }

 @Override
    public void onResume() {
        super.onResume();
    if (someConditionTrue) {
                mAddToList.setText(R.string.button_add_to_schedule);
                mAddToList.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_add_circle_outline_black_24dp, 0, 0, 0);

    } else {
                mAddToList.setText(R.string.button_update_firmware);
                mAddToList.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
    }

}

除了添加可绘制对象之外,没有发生任何重大事情。我不确定如何解决这个问题。如果有人可以提供帮助,那就太好了。

最佳答案

顶部的ListFrament有“Leaking: YES”,这意味着它不应该被保存在内存中,这意味着问题在它之前的trace中。因此,您需要粘贴整个跟踪以获取帮助。找到“泄漏:”从“否”变为"is"的引用资料,您就会找到原因。原因绝对不是可绘制按钮。

关于android - AppCompatButton 上的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58537066/

相关文章:

android - 如何在android中制作自定义textview?

Android Activity 到 Service 类

Android 位置不准确

java - Android 中使用的布局文件可以是默认的,也可以是 mdpi 的

android - 将协程与 fragment 一起使用的最佳实践是什么?

android - fragment 内的 QR 扫描器

java - Intent 抽屉导航 fragment

java - "cannot find symbol method setOnDismissListener(<anonymous OnDismissListener>)"

java - 通过 JSON 检索 ImageView 中的图像

java - 无法将搜索栏与文本关联起来