从在 Android 的片段中实例化的 class 扩展 BottomSheetDialogFragment

Extend BottomSheetDialogFragment from a class instantiated in a fragment in Android

我有一个片段 (FragmentSearchResults),其中包含从数据库中检索到的结果,其中有一个按钮 "filters"。当用户点击这样的按钮时,将实例化扩展 BottomSheetDialogFragment 的 class (FiltersDialog),以便用户可以设置他的过滤器。当用户关闭 FiltersDialog activity 时,值从 FiltersDialog 传递到 FragmentSearchResults。

    public class FragmentSearchResults extends Fragment implements FiltersDialog.FilterListener {

        /* code */

        ImageButton btnFilter = myFragment.findViewById(R.id.btn_filters);
        btnFilter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showFilters();
            }
        });

    }

    private void showFilters() {
        FiltersDialog filtersDialog = new FiltersDialog();
        filtersDialog.show(((FragmentActivity) mContext).getSupportFragmentManager(), "argument");
    }

    @Override
    public void onAttach(@NotNull Context context) {
        super.onAttach(context);
        mContext = context;
    }

    @Override
    public void onFiltersSet(Map filters) {
        // apply filters selected by user
    }

    public interface FilterListener {
        void onFiltersSet(Map filters);
    }
}



public class FiltersDialog extends BottomSheetDialogFragment {

    private FilterListener mListener;
    private Map<String, Object> mFilters;

    public FiltersDialog() {
    }

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

        TextView txtSave = v.findViewById(R.id.txt_save_filters);

        mTxtSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onFiltersSet(mFilters);
            }
        });

        return v;
    }

    public interface FilterListener {
        void onFiltersSet(Map filters);
    }

    @Override
    public void onAttach(@NotNull Context context) {
        super.onAttach(context);

        if (context instanceof FilterListener) {
            mListener = (FilterListener) context;
        }
        else {
            // Here's the error, as the activity Home.java containing FragmentSearchResults
            // does not implement FilterListener, FragmentSearchResults does
            throw new RuntimeException(context.toString() + " must implement FilterListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }
}

问题是 FilterListener 需要在 FragmentSearchResults 中实现,但我传递的是 activity Home 上下文。

如何在片段中实现 FilterListener?

为什么不在 FiltersDialog 中创建方法,例如

public void setFiltersListener(FiltersDialog.FilterListener listener) {
   mListener = listener;
}

并在实例化对话框后简单地调用它。

FiltersDialog filtersDialog = new FiltersDialog();
filtersDialog.setFiltersListener(this);
filtersDialog.show(((FragmentActivity) mContext).getSupportFragmentManager(), "argument");

然后就可以在dialog中使用listener了。像这样

if (mListener != null) {
    mListener.onFiltersSet(mFilters);
}

How can I setup listener to the dialog?

FragmentonAttach 的参数是 FragmentHost(Activity). 因此,它不能类型转换为 FilterListener.

我建议在 FragmentDialog 中实现 FilterListener setter 的简单方法如下代码。

... in FiltersDialog
public void setListener(FilterListener listener) {
    mListener = listener;
}
...

... in FragmentSearchResults
private void showFilters() {
    FiltersDialog filtersDialog = new FiltersDialog();
    filtersDialog.setListener(this);
    filtersDialog.show(((FragmentActivity) mContext).getSupportFragmentManager(), "argument");
}
...
//When FragmentSearchResults recreated, FiltersDialog must also need to be recreated.

在这种情况下,更好的方法是使用 LiveData、ViewModel。使用共享 ViewModel 方法,可以通过位于其环境中的所有片段访问 Activity 级 ViewModel。

  • 创建一个 Activity 关卡 ViewModel
  • 在 ViewModel 中定义一个 LiveData
  • 当您的 "FragmentSearchResults" 第一次打开时,开始 观察它。
  • 当您打开 "FiltersDialog" 屏幕并单击保存按钮时,然后 post 到过滤器中的 LiveData 更改(您在此处有 activity 上下文, 您可以在此处获取 ActivityViewModel,从中获取 LiveData,post 对此 LiveData 的更改)
  • Now As "FragmentSearchResults" 已经在观察 LiveData,你会在这里得到回调,做出相应的改变。这样你的代码就会完全解耦。你会从 接口的喧嚣。