android - 添加 fragment 并调用 .replace() 导致添加的 fragment 中的内存泄漏

标签 android android-fragments leakcanary

我有一个带有 3 个选项卡的 BottomNavigationView。在每次选项卡单击时,它都会调用 .replace()

private void initBottomNavigation() {

        mBottomNavigation.setOnNavigationItemSelectedListener(menuItem -> {
            switch (menuItem.getItemId()) {
                case R.id.bottomnav_admin_home:                <---- Tab 1
                        getSupportFragmentManager().beginTransaction()
                                .replace(
                                        R.id.admin_fragment_container,
                                        new AdminHomeFragment(),
                                        Constants.FRAGMENT_ADMIN_HOME
                                )
                                .commit();
                    }

                    ...Tab two
                    ....Tab three

                    return true;
    ```
在我的第三个选项卡中,我有一个在 fragment 容器顶部添加 fragment 的按钮:
enter image description here
当我单击该按钮时,它会调用它以在 fragment 容器的顶部添加另一个 fragment :
getParentFragmentManager().beginTransaction()
                .add(
                        R.id.admin_fragment_container,
                        new DeactivateUserFragment(),
                        Constants.FRAGMENT_ADMIN_DEACTIVATE_USER
                )
                .addToBackStack(null)
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                .commit();
当我在 已添加 fragment ,我点击调用 .replace() 的第二个选项卡,它会导致我的 内存泄漏已添加 分段。
我已经减少了添加的 Fragment 中的所有代码,但我不知道为什么它仍然在泄漏。
添加 fragment 的完整代码:
public class DeactivateUserFragment extends Fragment{
    private static final String TAG = "FragmentDeactivatedUser";

    @BindView(R.id.recycler_view) RecyclerView mRecycler;

    @BindView(R.id.parent_layout) ViewGroup mParentLayout;

    @BindView(R.id.progress_bar) ProgressBar mProgressBar;

    private Context                mContext;
    private SimpleListUsersAdapter mAdapter;
    private ArrayList<UserInfo>    mList = new ArrayList<>();
    private DeactivateViewModel    mViewModel;
    private AuthStateManager mAuthStateManager;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getContext();

    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_admin_deactivate_user, container, false);
        ButterKnife.bind(this, view);



        return view;
    }

    
    @OnClick(R.id.btn_back)
    public void onBackBtnClick(){
        getParentFragmentManager().popBackStack();
    }


}
泄漏:
androidx.coordinatorlayout.widget.CoordinatorLayout instance
​     Leaking: YES (ObjectWatcher was watching this because com.example.
​     testproject.ui.admin.deactivate.DeactivateUserFragment received
​     Fragment#onDestroyView() callback (references to its views should be
​     cleared to prevent leaks))
​     Retaining 106.7 kB in 1469 objects
​     key = e50280e9-58bd-4ecd-bc1b-a2d6cc188639
​     watchDurationMillis = 108539
​     retainedDurationMillis = 103532
​     View not part of a window view hierarchy
​     View.mAttachInfo is null (view detached)
​     View.mID = R.id.parent_layout
​     View.mWindowAttachCount = 1
​     mContext instance of com.example.testproject.ui.admin.AdminActivity
​     with mDestroyed = false
编辑 1:________________________________
为什么删除这三行不再导致内存泄漏?
@BindView(R.id.recycler_view) RecyclerView mRecycler;

    @BindView(R.id.parent_layout) ViewGroup mParentLayout;

    @BindView(R.id.progress_bar) ProgressBar mProgressBar;
我没有在任何代码中使用变量,只是将它们绑定(bind)。
我非常困惑这是如何导致泄漏的
编辑 2:__________________________________
我尝试在 onDestroyView() 中将 View 设置为 null和解开Butterknife,但仍然泄漏。
https://github.com/JakeWharton/butterknife/issues/585
 @Override
    public void onDestroyView() {
        Log.d(TAG, "onDestroyView: Called");
        unbinder.unbind();
        mRecycler = null;
        mParentLayout = null;
        mProgressBar = null;
        super.onDestroyView();
    }
我试过一一删除 View ...进度条、回收器和 mParentLayout。只有在我删除所有 3 个之前,它才不再泄漏
我从 fragment 中删除了 Butterknife 并且只使用 findViewById 但仍然有同样的问题

最佳答案

修复是为黄油刀的 Binder 设置一个全局变量。在我的 fragment 中并调用 UnbindonDestroyView()

private Unbinder unbinder;
@Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_admin_link_family, container, false);
        
        return view;
    }
我也绑定(bind)了我的适配器private SimpleListUsersAdapter adapter;
Inside Adapter class


 class ViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.action_type)
        TextView userAction;
        @BindView(R.id.date)
        TextView date;
        @BindView(R.id.amount)
        TextView amount;

        ViewHolder(@NonNull View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
所以我还需要在 onDestroyView 中将适配器设置为 null
Fragment Class

@Override
    public void onDestroyView() {
        super.onDestroyView();
        adapter = null;
        unbinder.unbind();
}
需要同时做以阻止泄漏

关于android - 添加 fragment 并调用 .replace() 导致添加的 fragment 中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66403565/

相关文章:

java - 将 Material 日期选择器值添加到 TextView

android - leakcanary stacktrace 难以理解

android - 如何从 Android 手机获取 GPS 数据?

java - Android 布局的内部类

android - 使用 Adob​​e Flash Media Server 的 RTMP 视频流

java - 无法解析方法 show(android.support.v4.app FragmentManager,java.lang.string)

java - 使用时间选择器使警报管理器每天重复

java - 如何将 Google Map API v2 包含到 fragment 中?

android - 了解 ViewTreeObserver 泄漏

Android 泄漏金丝雀 - 泄漏空 Activity