This mini-library is an another attempt to simplify how you create a RecyclerView.Adapter. It is written in Kotlin with Java in mind.
I know there are tons of RecyclerView.Adpater out there solving different problems. But sometimes you don't need all those functionalties they offer and you are tired of writing all the boilerplate code again and again.
Let RvListAdapter helps you.
##Features
- Built-in
List<T>
- Built-in
onItemClickListener
DiffUtil
support
##Download
//build.gradle
repositories {
jcenter()
}
dependencies {
compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.blacklenspub:rvlistadapter:1.1.0'
}
##How to use
###Creating ViewHolder
You would extend your ViewHolder from ItemViewHolder<T,VH>
.
A generic parameter T
would be the type of your item. A VH
is the type of your concrete implementation of the ItemViewHolder
- it is weired but it has to be there to support OnItemClickListener<T,VH>
.
In case you have multiple clickable views in your layout, there is a handy method callOnClick(View)
to notify your OnItemClickListener
of any child view clicked. But if you only interested in a whole itemView click event, you can ignore this - it has been done for you.
public class Student {
public long id;
public String name;
public String house;
public Student(long id, String name, String house) {
this.id = id;
this.name = name;
this.house = house;
}
}
class StudentHolder extends ItemViewHolder<Student, StudentHolder> {
TextView tvName = (TextView) itemView.findViewById(R.id.tvName);
TextView tvHouse = (TextView) itemView.findViewById(R.id.tvHouse);
StudentHolder(@NotNull View itemView) {
super(itemView);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
callOnClick(view);
}
});
tvHouse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
callOnClick(view);
}
});
}
}
###Creating Adapter
You override onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater)
and onBindViewHolder(StudentHolder holder, int position, T item)
like you always do but with extra handy parameters.
public class StudentAdapter extends RvListAdapter<Student, StudentAdapter.StudentHolder> {
public StudentAdapter(@Nullable List<? extends Student> list, @Nullable OnItemClickListener<Student, StudentHolder> onItemClick, @Nullable DiffCalculator<Student> diff) {
super(list, onItemClick, diff);
}
@NotNull
@Override
public StudentHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType, @NotNull LayoutInflater inflater) {
return new StudentHolder(inflater.inflate(R.layout.item_student, parent, false));
}
@Override
public void onBindViewHolder(@NotNull StudentHolder holder, int position, @NotNull Student item) {
holder.tvName.setText(item.name);
holder.tvHouse.setText(item.house);
}
}
Now, the constructor is a little bit confusing, it accepts 3 parameters - a List<T>
, an OnItemClickListener<T,VH>
and a DiffCalculator
.
- A
List<T>
is an initial list of your items. A null indicates an empty list. - An
OnItemClickListener<T,VH>
is how you listen for click events, leave it null if you don't want to. - A
DiffCalculator<T>
is there to supportDiffUtil
. Leave it null if you just want a simplenotifyDataSetChanged()
.
###OnItemClickListener
Let's have a look at the interface OnItemCliclListener<T,VH>
public interface OnItemClickListener<T, VH> {
void onItemClick(@NotNull View view, int position, @NotNull VH holder, @NotNull T item);
}
View view
is a view receiving a click event.int position
is basically agetAdapterPosition()
VH holder
is an instance of your ViewHolder.T item
is an item in the list at thatposition
.
###DiffCalculator
public interface DiffCalculator<T> {
DiffUtil.DiffResult getDiffResult(@NotNull List<T> oldList, @NotNull List<T> newList);
}
Basically you have to return a DiffUtil.DiffResult
based on oldList and newList. Then the RvListAdapter will dispatch the update accordingly everytime the items changed. See DiffUtil.
There is a SimpleDiffCalculator<T>
which simply check the lists' size and T.equals
.
###Put it all together
class StudentDiffCalculator implements DiffCalculator<Student> {
@Override
public DiffUtil.DiffResult getDiffResult(@NotNull final List<Student> oldList, @NotNull final List<Student> newList) {
return DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override
public int getOldListSize() {
return oldList.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).id == newList.get(newItemPosition).id;
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Student oldStudent = oldList.get(oldItemPosition);
Student newStudent = newList.get(newItemPosition);
if (oldStudent.name.equals(newStudent.name)) {
return false;
}
if (oldStudent.house.equals(newStudent.house)) {
return false;
}
return true;
}
});
}
}
StudentAdapter adapter = new StudentAdapter(
getInitialStudents(),
new OnItemClickListener<Student, StudentAdapter.StudentHolder>() {
@Override
public void onItemClick(@NotNull View view, int position, @NotNull StudentAdapter.StudentHolder holder, @NotNull Student item) {
String msg = "";
if (view == holder.tvName) { //identify a clicked view
msg = item.name;
} else if (view == holder.tvHouse) {
msg = item.house;
} else if (view == holder.itemView) {
msg = "Student ID: " + item.id;
}
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
},
new StudentDiffCalculator()
);
###Manipulate items
adapter.add(new Student(...)); //add an item
adapter.addAll(getMoreStudent()); //add a collection of items
adapter.setList(getAWholeNewListOfStudent()); //replace a list
adapter.remove(aStudent); //remove an item
adapter.removeAll(theseStudents); //remove a collection of items
There's no need to call notifyDataSetChanged()
afterwards.
Take a look at the sample project if this guide confuses you (sorry for that).