【问题标题】:Floating action button causing memory leak浮动操作按钮导致内存泄漏
【发布时间】:2019-07-16 14:30:07
【问题描述】:

我正在开发一个应用程序,该应用程序正在使用leak canary 检测possible memory leaks。该应用程序似乎很好,除了我的extended floating action button,根据leak canary,按钮泄漏,我不知道如何纠正这个问题。

下面是我的 XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fragments.store.StoreFragment">


    <com.google.android.material.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="@dimen/small_margin"
        app:cardElevation="@dimen/normal_elevation"
        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlayLargeCutLeftTopCorner">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipeToRefresh"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <androidx.core.widget.NestedScrollView
                android:id="@+id/nestScrollView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fadingEdge="vertical">

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


                    <ViewStub
                        android:id="@+id/layoutCategories"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:inflatedId="@+id/panel_layoutCategories"
                        android:layout="@layout/store_layout_categories" />


                    <ViewStub
                        android:id="@+id/layoutDeals"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:inflatedId="@+id/panel_layoutDeals"
                        android:layout="@layout/store_layout_deals" />


                    <ViewStub
                        android:id="@+id/layoutCollections"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:inflatedId="@+id/panel_layoutCollections"
                        android:layout="@layout/store_layout_collections" />
                </LinearLayout>

            </androidx.core.widget.NestedScrollView>
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
        android:id="@+id/btnGoToCart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:text="@string/cart"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        app:backgroundTint="@color/colorAccent"
        app:elevation="@dimen/large_elevation"
        app:icon="@drawable/ic_shopping_cart_24px"
        app:iconTint="@android:color/white"
        app:layout_anchor="@id/nestScrollView"
        app:layout_anchorGravity="bottom|end"
        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlayLargeCutLeftTopCorner" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

还有我的 Java 代码


public class StoreFragment extends Fragment implements View.OnClickListener {

   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_store, container, false);
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }


    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ButterKnife.bind(this, view);
  btnGoToCart.setOnClickListener(this);
     }



  @Override
    public void onClick(View v) {

        switch (v.getId()) {
                ....
            case R.id.btnGoToCart:
                Navigation.findNavController(v).navigate(R.id.cartFragment);
                break;
                ....
                }
              }
}

下面是泄漏金丝雀的 sn-p。起初leak 指向coordinator layout 的ID,我删除了它,现在它指向Extended floating action button

【问题讨论】:

    标签: android memory-leaks floating-action-button


    【解决方案1】:

    为什么不直接创建一个新的 OnClickListner 内部类,而不是让 Fragment 实现 OnClickListener?从我看到的情况来看,您将片段作为 OnClickListener 传递,并且该视图稍后会引用您的片段,这可能是泄漏的原因。只需执行 (new OnClickListener () {});而不是实现 OnClickListener。

    编辑: 我刚刚注意到您在 Fragment 中使用 ButterKnife。 如果你在 Fragment 中使用 ButterKnife,你应该使用:

    private Unbinder unbinder;
    
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fancy_fragment, container, false);
        unbinder = ButterKnife.bind(this, view);
        // TODO Use fields...
        return view;
    }
    
    @Override public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }
    

    绑定重置片段的视图生命周期不同于 活动。在 onCreateView 中绑定片段时,将视图设置为 在 onDestroyView 中为空。 Butter Knife 在以下情况下返回一个 Unbinder 实例 您调用 bind 为您执行此操作。在 适当的生命周期回调。

    【讨论】:

    • 我遇到了与问题中描述的相同的问题。我尝试了新的 OnClickListener(v -> doSomething() 作为 lambda 表达式),但它仍然显示 Leak Canary 中的泄漏。
    猜你喜欢
    • 2021-03-04
    • 1970-01-01
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    • 2016-01-18
    • 2012-12-13
    • 1970-01-01
    相关资源
    最近更新 更多