【问题标题】:What is the recommended way to launch a DialogFragment from a ViewModel?从 ViewModel 启动 DialogFragment 的推荐方法是什么?
【发布时间】:2017-03-14 10:13:14
【问题描述】:

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

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

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

那么我怎样才能显示对话框呢?

谢谢,欧维

【问题讨论】:

  • 从概念上讲,ViewModel 让我觉得启动对话框的位置错误。为了更清楚地做到这一点,我会将 RecyclerView.ViewHolder 传递到布局中,并在 ViewHolder 上有一个方法来触发 RecyclerView.Adapter 上的自定义侦听器。然后订阅该侦听器(活动/片段)的任何人都可以启动对话框。可能看起来有点迂回,但我认为列表项的 ViewModel 不应该了解或控制其环境。
  • @Ulli 我同意。您能否将其添加为答案?

标签: java android mvvm android-databinding


【解决方案1】:

从概念上讲,我认为 ViewModel 是启动对话框的错误位置。为了更清楚地做到这一点,我会将 RecyclerView.ViewHolder 传递到布局中,并在 ViewHolder 上有一个方法来触发 RecyclerView.Adapter 上的自定义侦听器。然后订阅该侦听器(活动/片段)的任何人都可以启动对话框。可能看起来有点迂回,但我认为列表项的 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);
            }
        }
    }
}

【讨论】:

    【解决方案2】:

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

    根据需要生成一个名为 context 的特殊变量,用于绑定表达式。上下文的值是来自根视图getContext() 的上下文。上下文变量将被具有该名称的显式变量声明覆盖。

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

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

    【讨论】:

    • 在 ViewModel 模式中使用这样的上下文可以吗?
    • @ashishdhiman2007 我认为 ViewModel 中上下文的真正问题是当你持有一个引用时。
    • 这会滥用 ViewModel 成为一种 Presenter。 ViewModel 负责 View 中的 数据(可能是带有关联 XML 数据绑定布局的 Fragment 或 Activity)。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        <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) -&gt; viewModel.onClick(view)}" 语句将当前视图作为参数,因此您可以在 ViewModel 中使用它来获取 view.getContext() 的上下文,如 Bayoudh 所述。

        【讨论】:

        • 你也可以使用方法参考android:onClick="@{viewModel::onClick}"
        • @tynn 你是什么意思?这不是我在答案中所指的吗?如果您没有将视图作为参数传递,您如何获得活动参考?
        • 和你写的一样,只是更短。只是想指出这一点。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 2020-01-30
        • 1970-01-01
        • 2017-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多