数据绑定Recyclerview和onClick [英] Databinding Recyclerview and onClick

查看:77
本文介绍了数据绑定Recyclerview和onClick的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Ok I'll try one more time. Last time I asked about passing data between recyclerview and item and one person helped me with open item by click, but I still don't have idea how to show the data of clicked item in new activity. I want to click on an item and then display the data of that item in new activity. In this activity I want to edit data. Does anyone knows how to do it? I need any idea.

具有OnItemClickListener接口的RecyclerView适配器:

RecyclerView Adapter with OnItemClickListener interface:

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>

onCreate:

@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);

推荐答案

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

Here are a couple of suggestions you might find useful:

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

Don't depend on ViewModels in your adapters. ViewModels are meant to handle events from views (Fragments or Activities) and broadcast updates back to the views via some observable mechanism (most commonly LiveData instances). Referencing your ViewModels directly inside an adapter is bad, since it couples them together. This means that it will be very hard for you to reuse your adapter with a different ViewModel if needed. I know it doesn't seem likely at this point in time, but just trust me on this one. After the changes have been applied, your adapter should look something like this:

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(),未将on click侦听器设置为适配器级别.

The OnItemClickListener.onItemClick() method now passes the view and the item itself as parameters. This is the easiest way to expose the clicked item to whoever might be interested. The on click listener is not set at the adapter level, using setOnItemClickListener().

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

The setting of the OnClickListener of the item view is now done in the bind() method of the TaskViewHolder. When binding, we know the exact item that is going to populate the view, so we can return it to the OnItemClickListener.

您还必须简化布局,因为确实不需要很多东西.可能看起来像这样:

You have to simplify the layout as well, since there are a lot of things that are not really needed. It may look like this:

<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>

唯一的变量是item,我们将其属性绑定到TextView.

The only variable is the item and we are binding it's properties to the TextViews.

我想这应该足以使您前进.

I guess this should be enough to get you going.

还有其他与问题没有直接关系但很重要的其他事情.

Just a couple of other things that are not directly related to the question, but are important.

  • 无安全措施-在适配器中调用setTask()时,您永远不会检查输入.客户端可能通过null并导致整个地方崩溃.您应该尝试防止这种情况.
  • 使用RecyclerView.Adapter时,调用notifyDataSetChanged()不是一个好习惯,因为这将取消RecyclerView的所有内置动画.最好使用其他notify...方法.您可能需要检查DiffUtil.
  • Null safety - you never check the input when calling setTask() in the adapter. A client may pass null and cause crashes all over the place. You should try and prevent that.
  • Calling notifyDataSetChanged() is not a good practice when working with RecyclerView.Adapter since this will cancel all the built-in animations of the RecyclerView. It's better to use the other notify... methods. You might want to check DiffUtil at some point.

这篇关于数据绑定Recyclerview和onClick的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆