数据绑定Recyclerview和onClick

时间:2018-11-09 21:14:21

标签: android mvvm android-recyclerview android-mvvm

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

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

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

3 个答案:

答案 0 :(得分:0)

这取决于数据的存储方式以及在第二个活动中是否可以访问。如果您的数据具有静态ArrayList,则可以使用在RV项目的onclick中传递的索引从数据中提取数据。例如:

class myData{
private ArrayList<Data> myDataArray;

static ArrayList<Data> getMyDataArray(){
   return myDataArray;
}

static void setMyDataArray(array)
   myDataArray = array;
}  

因此,您用getMyDataArray()填充RV,然后设置onlclick以将RV中单击的索引发送到下一个活动。 在第二个活动的onLoad中:

int myDataIndex = getIntent().getIntExtra("id",0);
Data myData = myData.getMyDataArray().get(myDataIndex);

注意:数据就是您的数据,可以是字符串,整数或带有数据的自定义类/对象。

答案 1 :(得分:0)

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

不依赖适配器中的ViewModelViewModel用于处理视图(片段或活动)中的事件,并通过某种可观察的机制(最常见的LiveData实例)将更新广播回视图。直接在适配器内部引用ViewModel是不好的,因为它将它们耦合在一起。这意味着如果需要,您将很难用另一个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()在适配器级别设置on click监听器。

现在通过OnClickListener的{​​{1}}方法对项目视图的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> ,我们将其属性绑定到item

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

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

  • 无安全措施-在适配器中调用TextView时永远不会检查输入。客户可能会通过setTask()并导致整个地方崩溃。您应该尝试防止这种情况。
  • 使用null时,调用notifyDataSetChanged()不是一个好习惯,因为这会取消RecyclerView.Adapter的所有内置动画。最好使用其他RecyclerView方法。您可能需要在某个时候检查notify...

答案 2 :(得分:0)

这是我使用数据绑定为回收者视图中的项目单击侦听器所做的事情。

适配器代码

public class TC_DashboardRecViewAdapter extends RecyclerView.Adapter<TC_DashboardRecViewAdapter.ViewHolder> {
Context context;
List<String> list;
private TcDashboardItemBinding tcDashboardItemBinding;
ItemClickListener itemClickListener;

public TC_DashboardRecViewAdapter(Context context, List<String> dashboardItems, ItemClickListener itemClickListener) {
    this.context = context;
    this.list = dashboardItems;
    this.itemClickListener = itemClickListener;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.tc_dashboard_item, parent, false);
    tcDashboardItemBinding = (TcDashboardItemBinding) parent.getTag();
    return new ViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.bind(list.get(position), itemClickListener, position);
}

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


class ViewHolder extends RecyclerView.ViewHolder {

    private ViewDataBinding binding;

    public ViewHolder(ViewDataBinding binding) {
        super(binding.getRoot());
        this.binding = binding;
    }

    public void bind(String s, ItemClickListener itemClickListener, int position) {
        this.binding.setVariable(BR.itemModel, s);
        this.binding.executePendingBindings();
        binding.getRoot().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(itemClickListener !=null){
                    itemClickListener.onItemClicked(binding.getRoot(), s, position);
                }
            }
        });
    }
}

项目点击界面:

public interface ItemClickListener {
void onItemClicked(View vh, Object item, int pos);
}

片段/活动代码:

public class TC_DashboardFragment extends BaseFragment implements ItemClickListener {


public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

 tc_dashboardRecViewAdapter = new TC_DashboardRecViewAdapter(getContext(), getDashboardItems(), this);
    linearLayoutManager = new LinearLayoutManager(getContext());
    dashboardrecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
    binding.setAdapter(tc_dashboardRecViewAdapter);
}

@Override
public void onItemClicked(View vh, Object item, int pos) {
    Toast.makeText(mainActivity, item.toString(), Toast.LENGTH_SHORT).show();
}

运行代码并单击“回收者视图”项目时,它将显示一个带有该项目中的文本的祝酒词。