如何去除ViewPager2中无用的片段

How to remove useless fragments in ViewPager2

如何在右交换时销毁ViewPager2中的retain Fragmentsunused FragmentsFragment与数字1-4)。我只想要 visible Fragment 左侧的 retain one Fragment(片段 5)?

private static class SettingAdapter extends FragmentStateAdapter {

    public SettingAdapter(@NonNull Fragment fragment) {
        super(fragment);
    }
    
    public void destroyUnusedFragment(){
        // ?
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Log.i("xxx", "createFragment: " + position);
        switch (position) {
            default:
            case 0:
                return new Fragment1();
            case 1:
                return new Fragment2();
            case 2:
                return new Fragment3();
            case 3:
                return new Fragment4();
            case 4:
                return new Fragment5();
            case 5:
                return new DispenserFragment();
            case 6:
                return new Fragment7();
            case 7:
                return new Fragment8();
            case 8:
                return new Fragment9();
            case 9:
                return new Fragment10();
            case 10:
                return new Fragment11();
            case 11:
                return new Fragment12();
            case 12:
                return new Fragment13();
            case 13:
                return new Fragment14();
            case 14:
                return new Fragment15();
        }
    }

    @Override
    public int getItemCount() {
        return 15;
    }
}


// call above from onCreateView in Fragment

String[] titles = getSettingTabTitlesRes(context);
settingAdapter = new SettingAdapter(this);

binding.settingViewpager.setOffscreenPageLimit(1);
binding.settingViewpager.setAdapter(settingAdapter);

new TabLayoutMediator(binding.settingTablayout, binding.settingViewpager, (tab, position) -> {
    tab.setText(titles[position]);
}).attach();

package id.ctech.dispenser_pos.ui.fragment.setting.dispenser.view;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import java.util.List;

import id.ctech.dispenser_pos.R;
import id.ctech.dispenser_pos.databinding.FragmentDispenserBinding;
import id.ctech.dispenser_pos.db.local.datasource.setting.dispenser.dispenser.DispenserDataSource;
import id.ctech.dispenser_pos.db.local.datasource.setting.dispenser.dispenser_brand.DispenserBrandDataSource;
import id.ctech.dispenser_pos.db.local.datasource.setting.nozzle.NozzleDataSourceHelper;
import id.ctech.dispenser_pos.db.local.datasource.setting.work_schedule.shift_work.ShiftWorkDataSourceHelper;
import id.ctech.dispenser_pos.db.local.datasource.setting.work_schedule.work_schedule.WorkScheduleDataSourceHelper;
import id.ctech.dispenser_pos.etc.ChooseColor;
import id.ctech.dispenser_pos.etc.ThreadExecutors;
import id.ctech.dispenser_pos.ui.activity.main.MainActivity;
import id.ctech.dispenser_pos.ui.compound.table.listeners.ITableDataClickListener;
import id.ctech.dispenser_pos.ui.compound.table.listeners.ITableDataLongClickListener;
import id.ctech.dispenser_pos.ui.fragment.etc.DebouncedOnClickListener;
import id.ctech.dispenser_pos.ui.fragment.setting.SettingFragment;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.model.Dispenser;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.model.DispenserBrand;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.presenter.DispenserPresenter;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.presenter.IDispenserPresenter;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.view.table.dispenser.DispenserDataAdapter;
import id.ctech.dispenser_pos.ui.fragment.setting.dispenser.view.table.dispenser_brand.DispenserBrandDataAdapter;
import id.ctech.dispenser_pos.ui.fragment.setting.nozzle.model.Nozzle;
import id.ctech.dispenser_pos.ui.fragment.setting.user_account.model.UserAccount;
import id.ctech.dispenser_pos.ui.fragment.setting.work_schedule.model.ShiftWork;
import id.ctech.dispenser_pos.ui.fragment.setting.work_schedule.model.WorkSchedule;

import static android.widget.Toast.LENGTH_SHORT;
import static id.ctech.dispenser_pos.dev.dispenser.ENozzleStatus.IN_HOLSTER;
import static id.ctech.dispenser_pos.etc.Common.ADMIN;
import static id.ctech.dispenser_pos.etc.Common.getDispenser;
import static id.ctech.dispenser_pos.etc.Common.getNozzles;
import static id.ctech.dispenser_pos.etc.Common.getShiftWorks;
import static id.ctech.dispenser_pos.etc.Common.getWorkSchedules;
import static id.ctech.dispenser_pos.etc.CommonColor.readThemeFromPref;
import static id.ctech.dispenser_pos.etc.CommonDate.toShortTime24;
import static id.ctech.dispenser_pos.ui.compound.alert_dialog.SweetAlertDialog.showConfirmDialog;
import static id.ctech.dispenser_pos.ui.compound.snackbar.SweetSnackbar.showSnackbarError;
import static id.ctech.dispenser_pos.ui.compound.snackbar.SweetSnackbar.showSnackbarInfo;
import static id.ctech.dispenser_pos.ui.compound.snackbar.SweetSnackbar.showSnackbarSuccess;


public class DispenserFragment extends Fragment implements IDispenserView {
    private final static int PREV_PAGE = 3;
    private final static int NEXT_PAGE = 5;
    private Context context;
    private IDispenserPresenter iDispenserPresenter;
    // Dispenser
    private DispenserDataAdapter dispenserDataAdapter;
    private Dispenser dispenserClicked = null, dispenserLongClicked = null;
    private int dispenserClickedRowIndex = -1, dispenserLongClickedRowIndex = -1;
    private int hiddenNewID;
    // DispenserBrand
    private DispenserBrandDataAdapter dispenserBrandDataAdapter;
    private DispenserBrand dispenserBrandClicked = null, dispenserBrandLongClicked = null;
    private int dispenserBrandClickedRowIndex = -1, dispenserBrandLongClickedRowIndex = -1;
    private int dispenserBrandNewID;
    private FragmentDispenserBinding binding;
    private ThreadExecutors threadExecutors;
    private UserAccount signInAccount;
    //
    private Dispenser dispenser;
    private Nozzle[] nozzles;
    private ShiftWork[] shiftWorks;
    private WorkSchedule[] workSchedules;
    private int nozzleQty;
    private int shiftWorkQty;

    public DispenserFragment() {
    }
    
    private void readDispenser() {
        try {
            dispenser = getDispenser(context);
            if (dispenser == null) {
                showSnackbarError(getString(R.string.message_failed_to_load_dispenser_module), LENGTH_SHORT);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void readNozzles() {
        try {
            nozzles = getNozzles(context);
            if (nozzles.length == 0) {
                showSnackbarError(getString(R.string.message_failed_to_load_nozzle_module), LENGTH_SHORT);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void readShiftWorks() {
        try {
            shiftWorks = getShiftWorks(context);
            if (shiftWorks.length == 0) {
                showSnackbarError(getString(R.string.message_failed_to_load_shift_work_module), LENGTH_SHORT);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void readWorkSchedules() {
        try {
            workSchedules = getWorkSchedules(context);
            if (workSchedules.length == 0) {
                showSnackbarError(getString(R.string.message_failed_to_load_work_schedule_module), LENGTH_SHORT);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void nozzleSync() {
        try {
            readDispenser();
            readNozzles();

            // nozzle sync
            if (dispenser != null && nozzles != null) {
                nozzleQty = dispenser.getNozzleQty(); // references
                if (nozzleQty < nozzles.length) {
                    for (int i = nozzleQty + 1; i <= nozzles.length; i++) {
                        NozzleDataSourceHelper.deleteNozzle(context, i);
                    }
                } else if (nozzleQty > nozzles.length) {
                    for (int i = nozzles.length + 1; i <= nozzleQty; i++) {
                        Nozzle nozzle = new Nozzle(i, i, 0, 0, 0, 0, IN_HOLSTER);
                        NozzleDataSourceHelper.createNozzle(context, nozzle);
                    }
                }
                nozzles = getNozzles(context);

                // nozzle validation
                nozzleQty = dispenser.getNozzleQty();
                if (nozzleQty != nozzles.length) {
                    showSnackbarError(getString(R.string.message_nozzle_sync_failed), LENGTH_SHORT);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void shiftWorkSync() {
        try {
            readDispenser();
            readShiftWorks();

            // shift work sync
            if (dispenser != null && shiftWorks != null) {
                shiftWorkQty = dispenser.getShiftWorkQty(); // references
                if (shiftWorkQty < shiftWorks.length) {
                    for (int i = shiftWorkQty + 1; i <= shiftWorks.length; i++) {
                        ShiftWorkDataSourceHelper.deleteShiftWork(context, i);
                    }
                } else if (shiftWorkQty > shiftWorks.length) {
                    for (int i = shiftWorks.length + 1; i <= shiftWorkQty; i++) {
                        String strTime24 = "";
                        switch (i) {
                            case 1:
                                strTime24 = "06:00";
                                break;
                            case 2:
                                strTime24 = "14:00";
                                break;
                            case 3:
                                strTime24 = "22:00";
                                break;
                        }
                        // create shift work
                        ShiftWork shiftWork = new ShiftWork(i, toShortTime24(strTime24));
                        ShiftWorkDataSourceHelper.createShiftWork(context, shiftWork);
                    }
                }
                shiftWorks = getShiftWorks(context);

                // shiftWorks validation
                shiftWorkQty = dispenser.getShiftWorkQty();
                if (shiftWorkQty != shiftWorks.length) {
                    showSnackbarError(getString(R.string.message_shiftworks_sync_failed), LENGTH_SHORT);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void workScheduleSync() {
        try {
            readDispenser();
            readWorkSchedules();

            // work schedule sync
            if (dispenser != null && workSchedules != null) {
                nozzleQty = dispenser.getNozzleQty(); // references
                if (nozzleQty < workSchedules.length) {
                    for (int i = nozzleQty + 1; i <= workSchedules.length; i++) {
                        WorkScheduleDataSourceHelper.deleteWorkSchedule(context, i);
                    }
                } else if (nozzleQty > workSchedules.length) {
                    for (int i = workSchedules.length + 1; i <= nozzleQty; i++) {
                        WorkSchedule workSchedule = new WorkSchedule(i, i, 1, 1, 1);
                        WorkScheduleDataSourceHelper.createWorkSchedule(context, workSchedule);
                    }
                }
                workSchedules = getWorkSchedules(context);

                // work schedule validation
                nozzleQty = dispenser.getNozzleQty();
                if (nozzleQty != workSchedules.length) {
                    showSnackbarError(getString(R.string.message_workschedule_sync_failed), LENGTH_SHORT);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void doSyncs() {
        try {
            nozzleSync();
            shiftWorkSync();
            workScheduleSync();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        try {
            Log.i("xxx", "DispenserFragment onCreateView");
            context = getActivity();
            if (context != null) {

                binding = FragmentDispenserBinding.inflate(inflater, container, false);
                View rootView = binding.getRoot();

                threadExecutors = ThreadExecutors.getInstance();

                doSyncs();

                DispenserDataSource dispenserDataSource = DispenserDataSource.getInstance(context);
                DispenserBrandDataSource dispenserBrandDataSource = DispenserBrandDataSource.getInstance(context);
                new DispenserPresenter(context, dispenserDataSource, dispenserBrandDataSource, this);

                // DispenserBrand
                binding.dispenserBrandAddButton.setOnClickListener(new DispenserBrandAddButtonClickListener());
                binding.dispenserBrandEditButton.setOnClickListener(new DispenserBrandEditButtonClickListener());
                binding.dispenserBrandDeleteButton.setOnClickListener(new DispenserBrandDeleteButtonClickListener());

                iDispenserPresenter.readDispenserBrands();

                // dispenser
                binding.dispenserPrevButton.setOnClickListener(new DispenserPrevButtonClickListener());
                binding.dispenserNextButton.setOnClickListener(new DispenserNextButtonClickListener());
                binding.dispenserAddButton.setOnClickListener(new DispenserAddButtonClickListener());
                binding.dispenserEditButton.setOnClickListener(new DispenserEditButtonClickListener());
                binding.dispenserDeleteButton.setOnClickListener(new DispenserDeleteButtonClickListener());

                signInAccount = ((MainActivity) getActivity()).getSignInAccount();

                iDispenserPresenter.readDispensers();

                setTheme(context);

                return rootView;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    private void setTheme(@NonNull Context context) {
        try {
            // set theme from pref
            ChooseColor chooseColor = readThemeFromPref(context);
            if (chooseColor != null) {
                context.setTheme(chooseColor.getTheme());     // app theme (default: R.style.app_theme_red)
            }

            Activity activity = getActivity();
            if (activity != null) {
                int colorPrimary = ((MainActivity) activity).getColorPrimary();

                binding.dispenserAddButton.setBackgroundColor(colorPrimary);
                binding.dispenserDeleteButton.setBackgroundColor(colorPrimary);
                binding.dispenserEditButton.setBackgroundColor(colorPrimary);

                binding.dispenserPrevButton.setBackgroundColor(colorPrimary);
                binding.dispenserNextButton.setBackgroundColor(colorPrimary);

                binding.dispenserBrandAddButton.setBackgroundColor(colorPrimary);
                binding.dispenserBrandDeleteButton.setBackgroundColor(colorPrimary);
                binding.dispenserBrandEditButton.setBackgroundColor(colorPrimary);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        Log.i("xxx", "DispenserFragment onDestroyView");

        binding = null;
        threadExecutors = null;
        dispenserBrandDataAdapter = null;
        dispenserBrandClicked = null;
        dispenserBrandLongClicked = null;
        dispenserDataAdapter = null;
        dispenserClicked = null;
        dispenserLongClicked = null;
    }

    @Override
    public void setPresenter(@NonNull IDispenserPresenter iPresenter) {
        iDispenserPresenter = iPresenter;
    }

    // DispenserBrand
    @Override
    public void onCreateDispenserBrand(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_successfully_to_save_data), LENGTH_SHORT);
                    iDispenserPresenter.readDispenserBrands();
                    binding.dispenserBrandAddButton.setText(getString(R.string.button_add));
                    binding.dispenserBrandEditButton.setEnabled(true);
                    binding.dispenserBrandDeleteButton.setEnabled(true);
                    binding.dispenserBrandAddButton.setTextColor(Color.WHITE);
                } else {
                    showSnackbarError(getString(R.string.message_failed_to_save_data), LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onReadDispenserBrands(@NonNull List<DispenserBrand> dispenserBrandList) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                dispenserBrandDataAdapter = new DispenserBrandDataAdapter(context, dispenserBrandList, binding.dispenserBrandTable);
                dispenserBrandDataAdapter.setSelectedColor(-1);
                binding.dispenserBrandTable.setDataAdapter(dispenserBrandDataAdapter);
                binding.dispenserBrandTable.sort(0, true);
                binding.dispenserBrandTable.invalidate();
                binding.dispenserBrandTable.removeDataClickListener(new DispenserBrandClickListener());
                binding.dispenserBrandTable.removeDataLongClickListener(new DispenserBrandLongClickListener());
                binding.dispenserBrandTable.addDataClickListener(new DispenserBrandClickListener());
                binding.dispenserBrandTable.addDataLongClickListener(new DispenserBrandLongClickListener());
                dispenserBrandClickedRowIndex = -1;
                dispenserBrandClicked = null;
                dispenserBrandLongClickedRowIndex = -1;
                dispenserBrandLongClicked = null;
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onUpdateDispenserBrand(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_successfully_to_save_data), LENGTH_SHORT);
                    iDispenserPresenter.readDispenserBrands();
                    binding.dispenserBrandEditButton.setText(getString(R.string.button_edit));
                    binding.dispenserBrandAddButton.setEnabled(true);
                    binding.dispenserBrandDeleteButton.setEnabled(true);
                    binding.dispenserBrandEditButton.setTextColor(Color.WHITE);
                } else {
                    showSnackbarError(getString(R.string.message_failed_to_save_data), LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onDeleteDispenserBrand(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_data_deleted), LENGTH_SHORT);
                } else {
                    showSnackbarError(getString(R.string.message_failed_to_delete_data), LENGTH_SHORT);
                }
                iDispenserPresenter.readDispenserBrands();
                binding.dispenserBrandAddButton.setEnabled(true);
                binding.dispenserBrandEditButton.setEnabled(true);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onNewIDDispenserBrand(int ID) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                dispenserBrandNewID = ID;
                dispenserBrandDataAdapter.add(new DispenserBrand(dispenserBrandNewID, ""));
                dispenserBrandDataAdapter.notifyDataSetChanged();
                binding.dispenserBrandTable.enterEditMode();
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onErrorDispenserBrand(@NonNull Throwable result) {
        Runnable r = () -> {

            try {
                String strMessage = result.getMessage();
                if (strMessage != null) {
                    showSnackbarError(strMessage, LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    // Dispenser
    @Override
    public void onCreateDispenser(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_successfully_to_save_data), LENGTH_SHORT);
                    iDispenserPresenter.readDispensers();
                    binding.dispenserAddButton.setText(getString(R.string.button_add));
                    binding.dispenserEditButton.setEnabled(true);
                    binding.dispenserDeleteButton.setEnabled(true);
                    binding.dispenserAddButton.setTextColor(Color.WHITE);

                    doSyncs();
                } else {
                    showSnackbarError(getString(R.string.message_failed_to_save_data), LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onReadDispensers(@NonNull List<Dispenser> result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                dispenserDataAdapter = new DispenserDataAdapter(context, result, binding.dispenserTable);
                dispenserDataAdapter.setSelectedColor(-1);
                binding.dispenserTable.setDataAdapter(dispenserDataAdapter);
                binding.dispenserTable.sort(0, true);
                binding.dispenserTable.invalidate();
                binding.dispenserTable.removeDataClickListener(new DispenserClickListener());
                binding.dispenserTable.removeDataLongClickListener(new DispenserLongClickListener());
                binding.dispenserTable.addDataClickListener(new DispenserClickListener());
                binding.dispenserTable.addDataLongClickListener(new DispenserLongClickListener());
                dispenserClickedRowIndex = -1;
                dispenserClicked = null;
                dispenserLongClickedRowIndex = -1;
                dispenserLongClicked = null;
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onUpdateDispenser(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_successfully_to_save_data), LENGTH_SHORT);
                    iDispenserPresenter.readDispensers();
                    binding.dispenserEditButton.setText(getString(R.string.button_edit));
                    binding.dispenserAddButton.setEnabled(true);
                    binding.dispenserDeleteButton.setEnabled(true);
                    binding.dispenserEditButton.setTextColor(Color.WHITE);

                    doSyncs();

                } else {
                    showSnackbarError(getString(R.string.message_failed_to_save_data), LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onDeleteDispenser(boolean result) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                if (result) {
                    showSnackbarSuccess(getString(R.string.message_data_deleted), LENGTH_SHORT);

                    doSyncs();

                } else {
                    showSnackbarError(getString(R.string.message_failed_to_delete_data), LENGTH_SHORT);
                }
                iDispenserPresenter.readDispensers();
                binding.dispenserAddButton.setEnabled(true);
                binding.dispenserEditButton.setEnabled(true);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    @Override
    public void onNewIDDispenser(int ID) {
        Runnable r = () -> {

            try {
                if (binding == null) {
                    return;
                }

                hiddenNewID = ID;
                // create default dispenser (dispenserId:1, dispenserType:new, nozzleQty:8, workScheduleQty:3)
                dispenserDataAdapter.add(new Dispenser(hiddenNewID, 1, 2, 8, 3));
                dispenserDataAdapter.notifyDataSetChanged();
                binding.dispenserTable.enterEditMode();
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }


    @Override
    public void onErrorDispenser(@NonNull Throwable result) {
        Runnable r = () -> {

            try {
                String strMessage = result.getMessage();
                if (strMessage != null) {
                    showSnackbarError(strMessage, LENGTH_SHORT);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        };
        threadExecutors.getMainThreadExecutor().execute(r);
    }

    // DispenserBrand
    private class DispenserBrandAddButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(final View v) {
        }
    }

    private class DispenserBrandEditButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }

    private class DispenserBrandDeleteButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }


    private class DispenserBrandClickListener implements ITableDataClickListener<DispenserBrand> {
        @Override
        public void onDataClicked(int rowIndex, DispenserBrand clickedData) {
        }
    }

    private class DispenserBrandLongClickListener implements ITableDataLongClickListener<DispenserBrand> {
        @Override
        public boolean onDataLongClicked(int rowIndex, DispenserBrand clickedData) {
            return false;
        }
    }


    // Dispenser
    private class DispenserPrevButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }

    private class DispenserNextButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }


    private class DispenserAddButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(final View v) {
        }
    }

    private class DispenserEditButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }

    private class DispenserDeleteButtonClickListener extends DebouncedOnClickListener {

        @Override
        public void onDebouncedClick(View v) {
        }
    }


    private class DispenserClickListener implements ITableDataClickListener<Dispenser> {
        @Override
        public void onDataClicked(int rowIndex, Dispenser clickedData) {
        }
    }

    private class DispenserLongClickListener implements ITableDataLongClickListener<Dispenser> {
        @Override
        public boolean onDataLongClicked(int rowIndex, Dispenser clickedData) {
            return false;
        }
    }

}

ViewPager2的bug,我得到的解决方法如下:

/**
 * Sets whether the LayoutManager should be queried for views outside of
 * its viewport while the UI thread is idle between frames.
 *
 * <p>If enabled, the LayoutManager will be queried for items to inflate/bind in between
 * view system traversals on devices running API 21 or greater. Default value is true.</p>
 *
 * <p>On platforms API level 21 and higher, the UI thread is idle between passing a frame
 * to RenderThread and the starting up its next frame at the next VSync pulse. By
 * prefetching out of window views in this time period, delays from inflation and view
 * binding are much less likely to cause jank and stuttering during scrolls and flings.</p>
 *
 * <p>While prefetch is enabled, it will have the side effect of expanding the effective
 * size of the View cache to hold prefetched views.</p>
 *
 * @param enabled <code>True</code> if items should be prefetched in between traversals.
 *
 * @see #isItemPrefetchEnabled()
 */
RecyclerView.LayoutManager layoutManager =  ((RecyclerView)(binding.settingViewpager.getChildAt(0))).getLayoutManager();
if(layoutManager != null) {
    layoutManager.setItemPrefetchEnabled(false);
}


/**
 * Set the number of offscreen views to retain before adding them to the potentially shared
 * {@link #getRecycledViewPool() recycled view pool}.
 *
 * <p>The offscreen view cache stays aware of changes in the attached adapter, allowing
 * a LayoutManager to reuse those views unmodified without needing to return to the adapter
 * to rebind them.</p>
 *
 * @param size Number of views to cache offscreen before returning them to the general
 *             recycled view pool
 */ 
RecyclerView recyclerView=  ((RecyclerView)(binding.settingViewpager.getChildAt(0)));
if(recyclerView != null) {
    recyclerView.setItemViewCacheSize(0);
}