底部 sheet 片段内存泄漏

Bottom sheet fragment memory leak

我正在使用 leakcanary,它说你的底部 sheet 片段正在泄漏。但是我看不出问题出在哪里。

我该如何修复泄漏?

public class TokensExplainedFragment extends BottomSheetDialogFragment implements HasSupportFragmentInjector {

    private static final String TAG = "TokensExplainedFragment";
    private View mainView;

    @Inject
    DispatchingAndroidInjector<Fragment> childFragmentInjector;

    @Inject
    SessionManager sessionManager;

    @Inject
    ViewModelProviderFactory providerFactory;

    public TokensExplainedFragment() {
    }

    @Override
    public void onAttach(Context context) {
        AndroidSupportInjection.inject(this);
        super.onAttach(context);
    }

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

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mainView = inflater.inflate(R.layout.fragment_tokens_explained, container, false);
        return mainView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);


        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

        return dialog;
    }

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return childFragmentInjector;
    }
}

我是这样开始的:

TokensExplainedFragment bottomSheetFragment = new TokensExplainedFragment();
bottomSheetFragment.show(getActivity().getSupportFragmentManager(), bottomSheetFragment.getTag());

泄漏痕迹:

getSupportFragmentManagergetFragmentManager 都是顶级 Activity 的片段管理器。要在片段级别内管理片段,请使用 getChildFragmentManager

bottomSheetFragment.show(getChildFragmentManager(), bottomSheetFragment.getTag());

根据 Android sources,ConnectivityThread 是:

Shared singleton connectivity thread for the system. This is a thread for connectivity operations such as AsyncChannel connections to system services. Various connectivity manager objects can use this singleton as a common resource for their handlers instead of creating separate threads of their own.

在这里我们可以看到这个线程是 运行,一条消息 post 发送给它并且当前在该线程上执行的消息引用了 TokensExplainedFragment。

我怀疑 TokensExplainedFragment 所做的比 Whosebug 中共享的要多(例如一些使用 sessionManager 的代码),并且在该额外代码中可能有调用连接系统服务的东西(例如 wifi、互联网、蓝牙等)。这可能会触发延迟 post 的消息到连接线程,并且 post 应该被取消但没有。