从 ViewModel 启动 DialogFragment 的推荐方法是什么?

What is the recommended way to launch a DialogFragment from a ViewModel?

我在 Recyclerview 中有一个列表对象。当长按一个项目时,我想显示一个对话框,其中包含单击项目的数据。

Recyclerview 正在为每个项目使用数据绑定,我可以在长按时使用 Log 显示所选项目的数据。

但是,当尝试显示对话框时,您需要访问 Activity,不建议在 ViewModel 对象中使用它。

那么如何显示对话框?

谢谢,欧维

因此您可以使用项目的上下文 itemView.getContext() 来显示 AlertDialog

Bayoudh 的提示将我引向了正确的方向,但我发布这个是为了将各个部分放在一起。下面是一个可点击的卡片视图。由于我的 ViewModel 没有引用 activity 我们必须将有问题的视图作为参数传递。

<android.support.v7.widget.CardView
        android:id="@+id/cardviewContact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/text_margin_0.5x"
        android:layout_marginRight="@dimen/text_margin_0.5x"
        android:layout_marginTop="@dimen/text_margin_0.5x"
        android:background="?attr/selectableItemBackground"
        android:clickable="true"
        android:minHeight="50dp"
        card_view:cardCornerRadius="4dp"
        android:onClick="@{(view) -> viewModel.onClick(view)}" >

android:onClick="@{(view) -> viewModel.onClick(view)}" 语句将当前视图作为参数,因此您可以在 ViewModel 中使用它来获取具有 view.getContext() 的上下文,如 Bayoudh 所述。

请参阅数据绑定库官方文档的 Variables 部分。在那里你找到了一个你可以使用的变量context

A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.

基本上您可以将它传递给另一个变量,例如 viewModel 以从那里显示对话框。

android:onClick="@{v -> viewModel.showDialog(context)}"

从概念上讲,我认为 ViewModel 是启动对话框的错误位置。为了更干净地做到这一点,我会将 RecyclerView.ViewHolder 传递到布局中,并在 ViewHolder 上使用一个方法来触发 RecyclerView.Adapter 上的自定义侦听器。然后订阅该侦听器 (Activity/Fragment) 的任何人都可以启动该对话框。可能看起来有点迂回,但我认为列表项的 ViewModel 不应该了解或控制其环境。

这是一个例子。这是使用数据绑定和 ViewModel 处理 RecyclerView 项目点击的通用模式。这不是一个完整的示例,只是突出显示此特定模式的代码。

布局:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <data>
    <variable
        name="viewHolder"
        type="com.example.ViewHolder"
        />
    <variable
        name="viewModel"
        type="com.example.ViewModel"
        />
    </data>

    <com.example.View
        android:layout_width="match_parent"
        android:layout_height="24dp"
        android:onClick="@{() -> viewHolder.onClick(viewModel)}"
        />
</layout>

适配器:

class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    public interface SelectionListener {
        void onSelectionChanged(int newPosition, ViewModel viewModel);
    }

    private @NonNull WeakReference<SelectionListener> selectionListener =
            new WeakReference<>(null);

    public void setSelectionListener(@Nullable SelectionListener listener) {
        selectionListener = new WeakReference<>(listener);
    }

    public class ViewHolder extends RecyclerView.ViewHolder<ViewBinding> {
        ViewHolder(ViewBinding binding) {
            super(binding.getRoot());

            binding.setViewHolder(this);
            binding.setViewModel(new ViewModel());
        }

        public void onClick(ViewModel viewModel) {
            SelectionListener listener = selectionListener.get();
            if (listener != null) {
                listener.onSelectionChanged(getAdapterPosition(), viewModel);
            }
        }
    }
}

我想为recyclerview使用一个绑定适配器,然后将适配器n ViewModel,然后使viewmodel成为片段的模型,并在xml本身的setAdapter方法中传递适配器。