简体   繁体   中英

Recycler-view data binding on click of row

What I am doing : I have displayed the list view using data binding

What I am trying to find : How to properly add a on click event and display a toast as student name

Student.java

public class Student {

    private  String name;
    private  String email;

    public Student() {
    }

    public Student(String name, String email) {
        this.name = name;
        this.email = email;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }


}

ActDemoListView.java

public class ActDemoListView extends AppCompatActivity {


    private ActDemoListViewViewModel actDemoListViewViewModel;
    private ActDemoListViewBinding actDemoListViewBinding;


    private RecyclerView recyclerView;
    private AdptStudent adptStudent;
    private List<Student> studentList = new ArrayList<>();

    /************************************* Life Cycle Methods *************************************/
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initOnCreate();
    }
    /************************************* Life Cycle Methods *************************************/

    /************************************* Init Methods *******************************************/
    /** Init OnCreate **/
    private void initOnCreate() {
        setContentView(R.layout.act_two_way_display_data);
        //Connect the view model to activity
        connectViewModel();
        //Bind the layout to activity
        bindLayoutToActivity();

        recyclerView = actDemoListViewBinding.recyclerList;
        adptStudent = new AdptStudent(studentList);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(adptStudent);

        prepareMovieData();
    }



    /************************************* Init Methods *******************************************/


    private void connectViewModel() {
        actDemoListViewViewModel = ViewModelProviders.of(this).get(ActDemoListViewViewModel.class);
    }

    private void bindLayoutToActivity() {
        actDemoListViewBinding = DataBindingUtil.setContentView(this,R.layout.act_demo_list_view);
    }

    private void prepareMovieData() {
        Student movie = new Student("Shruthi", "user11@google.com");
        studentList.add(movie);

        movie = new Student("Shalvi", "user1@google.com");
        studentList.add(movie);

        movie = new Student("Pavan", "user2@google.com");
        studentList.add(movie);

        movie = new Student("Brijesh", "user3@google.com");
        studentList.add(movie);

        movie = new Student("Anudeep", "user4@google.com");
        studentList.add(movie);

        adptStudent.notifyDataSetChanged();
    }

}

AdptStudent.java

public class AdptStudent extends RecyclerView.Adapter<AdptStudent.MyViewHolder> {


    private List<Student> studentsList = new ArrayList<>();


    public AdptStudent(List<Student> studentsList) {
        this.studentsList = studentsList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ListItemBinding listItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.list_item, parent, false);
        return new MyViewHolder(listItemBinding);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Student student = studentsList.get(position);
        holder.listItemBinding.setStudent(student);
    }

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

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private ListItemBinding listItemBinding;

        public MyViewHolder(ListItemBinding ListItemBinding) {
            super(ListItemBinding.getRoot());
            this.listItemBinding=ListItemBinding;
        }
    }


}

There are several ways to do it. When i want an item on a recycler view to be clickable i do this.

Firstly i create an interface

public interface ItemClickListener {
    void onClick(View view, int position, boolean click);
}

Secondly, on the view holder class i add these methods

    @Override
    public void onClick(View view) {
        itemClickListener.onClick(view, getAdapterPosition(), false);
    }

    public void setItemClickListener(ItemClickListener itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

And lastly on the onBindViewHolder

@Override
public void onBindViewHolder(@NonNull final CategoryAdapter.MyViewHolder myViewHolder, int i) {

    myViewHolder.setItemClickListener(new ItemClickListener() {
        @Override
        public void onClick(View view, int position, boolean click) {
            Intent intent = new Intent(myViewHolder.context, Myclass.class);
            myViewHolder.context.startActivity(intent);
        }
    });
}

If you want me to provide all the code for the adapter just ask.

I have used the following approach. Note that your "Item" can be your viewmodel if you like which you have access to inside the bound layout for each item. And from there you can call whatever method you want inside the vm, or set a LiveData or whatever to tell the view to display the toast. I recomment to use SingleLiveEvent for this purpose.

First I created a BaseAdapter.

public class BaseAdapter<T> extends ListAdapter<T, SingleItemViewHolder<T>> {

private final int variableId;

protected BaseAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback, int variableId) {
    super(diffCallback);
    this.variableId = variableId;
}

@NonNull
@Override
public SingleItemViewHolder<T> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    ViewDataBinding binding = DataBindingUtil.inflate(
            LayoutInflater.from(parent.getContext()), viewType, parent, false);

    return new SingleItemViewHolder<>(binding, variableId);
}

@Override
public void onBindViewHolder(@NonNull SingleItemViewHolder<T> holder, int position) {
    holder.bind(getItem(position));
}

}

This adapter uses the following SingleItemViewHolder.

public final class SingleItemViewHolder<T> extends RecyclerView.ViewHolder {

private final ViewDataBinding binding;

private final int variableId;

/**
 * Constructor
 *
 * @param binding the binding to use
 * @param variableId variable to set on the binding
 */
public SingleItemViewHolder(ViewDataBinding binding, int variableId) {
    super(binding.getRoot());
    this.binding = Objects.requireNonNull(binding);
    this.variableId = variableId;
}

/**
 * Sets the data binding variable to the provided item
 * and calls {@link ViewDataBinding#executePendingBindings()}.
 *
 * @param item item to bind
 * @throws NullPointerException if item is null ({@code item == null})
 */
public void bind(@NonNull T item) {
    Objects.requireNonNull(item);
    binding.setVariable(variableId, item);
    binding.executePendingBindings();
}
}

Then you use it by subclassing the BaseAdapter and providing your own DiffCallback and layout like this.

public final class ModelAdapter extends BaseAdapter<Model> {

public ModelAdapter() {
    super(new DiffCallback(), BR.item);
}

@Override
public int getItemViewType(int position) {
    return R.layout.item_model;
}

private static final class DiffCallback extends DiffUtil.ItemCallback<Model> {

    @Override
    public boolean areItemsTheSame(@NonNull Model oldItem, @NonNull Model newItem) {
        return oldItem.id.equals(newItem.id);
    }

    @Override
    public boolean areContentsTheSame(@NonNull Model oldItem, @NonNull Model newItem) {
        return oldItem.equals(newItem);
    }
}
}

Where Model is a simple java object class with some fields (not included for brevity).

Then the layout which shows the actual model and allows for the data binding.

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="item"
            type="com.example.models.Model" />
    </data>

    ....

Then you can simply use that item inside the layout.

Bonus usage example

Then instantiate it however you want. My recommendation, how I did it, was to instantiate in the view (fragment) the attach it using data binding.

<data>
    <variable
        name="adapter"
        type="com.example.ModelAdapter" />
</data>

....

<androidx.recyclerview.widget.RecyclerView
            recycler_view_base_adapter_items="@{vm.models}"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adapter="@{adapter}"
            android:orientation="vertical"
            android:scrollbars="vertical"             
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

With the following @BindingAdapter.

@BindingAdapter(value = {"recycler_view_base_adapter_items"})
public static <T> void setRecyclerViewBaseAdapterItems(RecyclerView view,
                                                       @Nullable final List<T> items) {

    final RecyclerView.Adapter viewAdapter = view.getAdapter();

    if (viewAdapter == null || items == null) {
        Timber.w("recycler_view_base_adapter_items did nothing.");
        return;
    }

    try {
        @SuppressWarnings("unchecked") final BaseAdapter<T> adapter = (BaseAdapter<T>) viewAdapter;
        adapter.submitList(items);

    } catch (ClassCastException e) {
        Timber.e(e);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM