android - 由于 Snackbar 导致的内存泄漏

标签 android memory-leaks leakcanary

我刚刚将 CanaryLeak 添加到我的项目中,以查看我的应用程序中是否存在任何内存泄漏,并注意到,由于 Snackbar,我的一个 fragment 中确实存在泄漏。

我在 onCreateView 中创建了一个 Snackbar,并在 onDestroyView 中将其设置为 null。但是,每次旋转屏幕时都会发生内存泄漏。


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup 
    container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_backend, container, 
        false);

        Activity parentActivity = getActivity();
        if (parentActivity != null) {
            mConnectSnackbar = 
            Snackbar.make(parentActivity.findViewById(R.id.nav_host_fragment), 
            "Connect", Snackbar.LENGTH_INDEFINITE);

            mConnectSnackbar.setAction(getString(R.string.connect), v -> 
            startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS)));
        }

        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mConnectSnackbar.setAction("Connect", null);
        mConnectSnackbar.dismiss();
        mConnectSnackbar = null;
    }

当我清除对操作和 Snackbar 本身的引用时,不应该有任何内存泄漏的原因。但是我无法弄清楚,原因可能是什么,来自 Canary Leak 的堆转储也无济于事。 由于引用了 nav_host_fragment,我怀疑这可能是我造成的,但我不知道这是否属实以及如何解决。

非常感谢您的帮助。

编辑 1:

添加了 Leak Trace 并删除了 hprof 文件。

┬
├─ android.view.accessibility.AccessibilityManager
│    Leaking: NO (a class is never leaking)
│    GC Root: System class
│    ↓ static AccessibilityManager.sInstance
│                                  ~~~~~~~~~
├─ android.view.accessibility.AccessibilityManager
│    Leaking: UNKNOWN
│    ↓ AccessibilityManager.mTouchExplorationStateChangeListeners
│                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
├─ android.util.ArrayMap
│    Leaking: UNKNOWN
│    ↓ ArrayMap.mArray
│               ~~~~~~
├─ java.lang.Object[]
│    Leaking: UNKNOWN
│    ↓ array Object[].[4]
│                     ~~~
├─ androidx.core.view.accessibility.AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper
│    Leaking: UNKNOWN
│    ↓ AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper.mListener
│                                                                            ~~~~~~~~~
├─ com.google.android.material.snackbar.BaseTransientBottomBar$SnackbarBaseLayout$1
│    Leaking: UNKNOWN
│    ↓ BaseTransientBottomBar$SnackbarBaseLayout$1.this$0
│                                                  ~~~~~~
╰→ com.google.android.material.snackbar.Snackbar$SnackbarLayout
​     Leaking: YES (View.mContext references a destroyed activity)
​     mContext instance of android.view.ContextThemeWrapper, wrapping activity com.twaice.twaice.MainActivity with mDestroyed = true
​     View#mParent is null
​     View#mAttachInfo is null (view detached)
​     View.mWindowAttachCount = 0

最佳答案

这是 material-components-android 库中的内存泄漏。我刚刚提交了一个问题:https://github.com/material-components/material-components-android/issues/497

只有创建了一个 snackbar 但从未像问题中描述的那样显示时才会发生此泄漏:

In Material Library 1.0.0, when a BaseTransientBottomBar .SnackbarBaseLayout instance is created, it registers a TouchExplorationStateChangeListener which it then unregisters onDetachedFromWindow(). If the SnackbarBaseLayout is created but never attached (which happens), then it never gets detached. When the underlying context (an activity) gets destroyed, the TouchExplorationStateChangeListener is kept in memory by AccessibilityManager, holding on to its outer class SnackbarBaseLayout which itself holds on to its context, a destroyed activity. Effectively SnackbarBaseLayout is leaking destroyed activities and the entire view hierarchy.

好消息是此代码在 1.1.0 版本中不再存在,因此泄漏已经消失,但不幸的是 1.1.0 仍处于 alpha 版本中。

注意:在以后的帖子中,考虑提供 LeakCanary 输出的文本泄漏跟踪,这对于解决内存泄漏很有用。

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

相关文章:

android - 如何降低我的应用程序的内存使用量?

android - 使用 App Widget 的 TouchDelegate?

silverlight - 为 Silverlight 行为自动调用 OnDetaching()

android - Square LeakCanary 找不到符号

android - 无法从 Leakcanary 的泄漏报告中检测到引用

android - 使用动态屏幕时如何防止内存泄漏?

android - 滚动到项目

ios - UIImagePickerController 在快速拍摄 2 3 张图片后导致泄漏

iphone - 为什么这会导致内存泄漏

Android BLE 启用通知