Расширить BottomSheetDialogFragment из класса, созданного во фрагменте в Android - PullRequest
0 голосов
/ 13 апреля 2020

У меня есть фрагмент (FragmentSearchResults), который содержит результаты, извлеченные из базы данных, в которой есть кнопка «Фильтры». Когда пользователь нажимает на такую ​​кнопку, создается экземпляр класса (FiltersDialog), расширяющего BottomSheetDialogFragment, чтобы пользователь мог установить свои фильтры. Когда пользователь закрывает действие FiltersDialog, значения передаются из 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, но я передаю контекст Home действия.

Как я могу реализовать FilterListener во фрагменте?

Ответы [ 3 ]

1 голос
/ 13 апреля 2020

Как мне настроить listener для диалогового окна?

Параметр onAttach в Fragment равен FragmentHost (Activity). таким образом, это не могу типизировать до FilterListener.

Я предлагаю простой способ реализации FilterListener setter в FragmentDialog, как показано ниже.

... 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.
1 голос
/ 13 апреля 2020

Почему бы вам не создать метод внутри FiltersDialog, например

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

, и просто вызвать его после создания диалогового окна.

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

Тогда вы можете использовать слушатель внутри диалога. как то так

if (mListener != null) {
    mListener.onFiltersSet(mFilters);
}
0 голосов
/ 13 апреля 2020

Лучшим подходом будет использование LiveData, в данном случае ViewModel. Используйте общий подход ViewModel, к ViewModel уровня активности можно получить доступ через все фрагменты, лежащие в его окружении.

  • Создание уровня активности ViewModel
  • Определение LiveData в ViewModel
  • Когда ваш «FragmentSearchResults» открывается в первый раз, начните наблюдать за ним.
  • Когда вы открываете экран «FiltersDialog» и нажимаете кнопку «Сохранить», затем публикуйте изменения в фильтре LiveData (здесь у вас есть контекст активности, Вы можете получить ActivityViewModel здесь, получить от нее LiveData, опубликовать изменения в этих LiveData)
  • Теперь, поскольку «FragmentSearchResults» уже наблюдает изменения в LiveData, вы получите обратный вызов здесь, внесите соответствующие изменения. Таким образом, ваш код будет полностью отделен. Вы будете спасены от шума интерфейсов.
...