首页 > 解决方案 > 数据绑定 Recyclerview 和 onClick

问题描述

好的,我再试一次。上次我询问在 recyclerview 和 item 之间传递数据,一个人通过点击帮助我打开了项目,但我仍然不知道如何在新活动中显示点击项目的数据。我想单击一个项目,然后在新活动中显示该项目的数据。在此活动中,我想编辑数据。有谁知道该怎么做?我需要任何想法。

带有 OnItemClickListener 接口的 RecyclerView 适配器:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {

private List<MainViewModel> mTasks;
private List<Task> tasks = new ArrayList<>();
private Context context;
private EditTaskViewModel editTaskViewModel;


public RecyclerViewAdapter(List<MainViewModel> tasks, Context context, EditTaskViewModel editTaskViewModel) {
    this.mTasks = tasks;
    this.context = context;
    this.editTaskViewModel = editTaskViewModel;
}


@NonNull
@Override
public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    final RecyclerViewItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.recycler_view_item, parent, false);

    binding.setItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(View view) {
            Intent intent = new Intent(view.getContext(), EditTaskActivity.class);
            intent.putExtra("id", binding.getPosition());
            view.getContext().startActivity(intent);
            Toast.makeText(view.getContext(), "ID " + binding.getPosition(), Toast.LENGTH_SHORT).show();

        }
    });
    return new TaskViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
    Task currentTask = tasks.get(position);
    holder.mBinding.descriptionItem.setText(currentTask.getDescription());
    holder.mBinding.dateItem.setText(currentTask.getDate());
    holder.mBinding.timeItem.setText(currentTask.getTime());
    holder.mBinding.setPosition(position);
}

@Override
public int getItemCount() {
    return tasks.size();
}

public void setTasks(List<Task> tasks) {
    this.tasks = tasks;
    notifyDataSetChanged();
}

public Task getTaskPosition(int position) {
    return tasks.get(position);
}

public class TaskViewHolder extends RecyclerView.ViewHolder {
    private final RecyclerViewItemBinding mBinding;

    public TaskViewHolder(RecyclerViewItemBinding binding) {
        super(binding.getRoot());
        this.mBinding = binding;
    }

        public void bind (MainViewModel mainViewModel){
            mBinding.setItemView(mainViewModel);
            mBinding.executePendingBindings();
        }
    }

    public interface OnItemClickListener {
        void onItemClick(View view);
    }

项目 XML 文件:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
    <variable
        name="itemView"
        type="com.example.daniellachacz.taskmvvm.viewmodel.MainViewModel">
    </variable>

    <variable
        name="itemClickListener"
        type="com.example.daniellachacz.taskmvvm.adapter.RecyclerViewAdapter.OnItemClickListener">
    </variable>

    <variable
        name="task"
        type="com.example.daniellachacz.taskmvvm.model.Task">
    </variable>

    <variable
        name="position"
        type="int">
    </variable>

</data>

<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:shadowColor="@color/colorPrimary"
android:backgroundTint="@color/cardview_shadow_end_color">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:onClick="@{(view)-> itemClickListener.onItemClick(view)}">

<TextView
    android:id="@+id/description_item"
    android:layout_width="250dp"
    android:layout_height="96dp"
    android:layout_marginStart="5dp"
    android:layout_marginTop="9dp"
    android:layout_marginBottom="5dp"
    android:text="@{itemView.description}"
    android:textSize="18sp"
    android:textColor="#020202"
    android:focusable="true" />

<TextView
    android:id="@+id/date_item"
    android:layout_width="90dp"
    android:layout_height="40dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentEnd="true"
    android:layout_marginTop="9dp"
    android:layout_marginEnd="10dp"
    android:gravity="center"
    android:text="@{itemView.date}"
    android:textColor="#020202"
    android:textSize="16sp" />

<TextView
    android:id="@+id/time_item"
    android:layout_width="90dp"
    android:layout_height="40dp"
    android:layout_alignParentBottom="true"
    android:layout_alignStart="@+id/date_item"
    android:layout_marginBottom="10dp"
    android:layout_marginEnd="10dp"
    android:gravity="center"
    android:text="@{itemView.time}"
    android:textColor="#020202"
    android:textSize="16sp" />

    </RelativeLayout>
    </android.support.v7.widget.CardView>

    </layout>

创建:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

floatingActionButton = findViewById(R.id.floating_action_button);

List<Task> tasks = new ArrayList<>();

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);

final RecyclerViewAdapter recyclerViewAdapter = new     RecyclerViewAdapter(context, tasks);
recyclerView.setAdapter(recyclerViewAdapter);

mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
mainViewModel.getAllTasks().observe(this, recyclerViewAdapter::setTasks);

标签: androidmvvmandroid-recyclerviewandroid-mvvm

解决方案


以下是一些您可能会觉得有用的建议:

不要依赖ViewModel适配器中的 s 。ViewModels 旨在处理来自视图(片段或活动)的事件,并通过一些可观察的机制(最常见的LiveData实例)将更新广播回视图。直接在适配器内引用你ViewModel的 s 是不好的,因为它将它们耦合在一起。这意味着如果需要,您将很难使用不同的适配器重用您的适配器ViewModel。我知道目前似乎不太可能,但请相信我。应用更改后,您的适配器应如下所示:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {

    private LayoutInflater mLayoutInflater;
    private List<Task> mTasks;

    private OnItemClickListener mOnItemClickListener;

    public RecyclerViewAdapter(@NonNull Context context, @NonNull List<Task> tasks) {
         mLayoutInflater = LayoutInflater.fromContext(context);
         mTasks = tasks;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }
    
    @NonNull
    @Override
    public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        final RecyclerViewItemBinding binding = DataBindingUtil.inflate(mLayoutInflater, R.layout.recycler_view_item, parent, false);
        return new TaskViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
        Task currentTask = tasks.get(position);
        holder.bind(currentTask, mOnItemClickListener);
    }

    @Override
    public int getItemCount() {
        return tasks.size();
    }

    public void setTasks(List<Task> tasks) {
        this.tasks = tasks;
        notifyDataSetChanged();
    }

    public Task getTaskPosition(int position) {
        return tasks.get(position);
    }

    public class TaskViewHolder extends RecyclerView.ViewHolder {
        private final RecyclerViewItemBinding mBinding;

         public TaskViewHolder(RecyclerViewItemBinding binding) {
             super(binding.getRoot());
             this.mBinding = binding;
         }

         public void bind (Task item, OnItemClickListener onItemClickListener) {
             mBinding.setItem(item);
             mBinding.executePendingBindings();
             itemView.setOnClickListener(view -> {
                 if (onItemClickListener != null) {
                     onItemClickListener.onItemClick(view, item);
                 }
             }
         }
    }

    public interface OnItemClickListener {
        void onItemClick(View view, Task item);
    }
}

OnItemClickListener.onItemClick()方法现在将视图和项目本身作为参数传递。这是向任何可能感兴趣的人公开单击的项目的最简单方法。点击监听器现在设置在适配器级别,使用setOnItemClickListener().

项目视图的设置OnClickListener现在在 的bind()方法中完成TaskViewHolder。绑定时,我们知道要填充视图的确切项目,因此我们可以将其返回给OnItemClickListener.

您还必须简化布局,因为有很多东西并不是真正需要的。它可能看起来像这样:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
    <variable
        name="task"
        type="com.example.daniellachacz.taskmvvm.model.Task">
    </variable>
</data>

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:shadowColor="@color/colorPrimary"
    android:backgroundTint="@color/cardview_shadow_end_color">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="110dp"
        android:layout_marginBottom="6dp"
        android:layout_marginTop="6dp"
        android:layout_marginStart="6dp"
        android:layout_marginEnd="6dp">

        <TextView
            android:id="@+id/description_item"
            android:layout_width="250dp"
            android:layout_height="96dp"
            android:layout_marginStart="5dp"
            android:layout_marginTop="9dp"
            android:layout_marginBottom="5dp"
            android:text="@{item.description}"
            android:textSize="18sp"
            android:textColor="#020202"
            android:focusable="true" />

        <TextView
            android:id="@+id/date_item"
            android:layout_width="90dp"
            android:layout_height="40dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="9dp"
            android:layout_marginEnd="10dp"
            android:gravity="center"
            android:text="@{item.date}"
            android:textColor="#020202"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/time_item"
            android:layout_width="90dp"
            android:layout_height="40dp"
            android:layout_alignParentBottom="true"
            android:layout_alignStart="@+id/date_item"
            android:layout_marginBottom="10dp"
            android:layout_marginEnd="10dp"
            android:gravity="center"
            android:text="@{item.time}"
            android:textColor="#020202"
            android:textSize="16sp" />

        </RelativeLayout>
    </android.support.v7.widget.CardView>

</layout>

唯一的变量是 the item,我们将它的属性绑定到TextViews。

我想这应该足以让你继续前进。

只是与问题没有直接关系但很重要的其他几件事。

  • setTask()空安全 -在适配器中调用时,您永远不会检查输入。客户端可能会通过null并导致到处崩溃。您应该尝试防止这种情况发生。
  • 使用时调用notifyDataSetChanged()不是一个好习惯,RecyclerView.Adapter因为这将取消RecyclerView. 最好使用其他notify...方法。您可能想DiffUtil在某个时候进行检查。

推荐阅读