Lập trình Android cơ bản

Bài 11: RecyclerView trong Android

1. Giới thiệu RecyclerView

RecyclerView nó dùng để xây dựng UI gần giống với hoạt động của ListView, GridView. Nó biểu diễn danh sách với nhiều cách trình bày khác nhau, theo chiều đứng, chiều ngang. Nó là thư viện hỗ trợ tốt hơn ListView rất nhiều nhất ra sử dụng trong CoordinatorLayout để tương tác với các thành phần UI khác.
RecyclerView cũng rất phù hợp khi dữ liệu hiện thị thu thập trong quá trình chạy ứng dụng, như căn cứ vào tương tác người dùng, vào dữ liệu tải về .
Điều đầu tiên muốn sử dụng RecyclerView thì bạn phải tích hợp vào build.gradle thư viện như sau để sử dụng.
implementation 'com.android.support:design:29.0.1'
Khi dùng đến RecylerView thì bạn cũng cần làm việc với:
  1. RecyclerView.Adapter Quản lý dữ liệu và cập nhật dữ liệu cần hiện thị vào View (phần tử hiện thị trong RecyclerView)
  2. RecyclerView.LayoutManager Lớp mà để quy định cách mà vị trí các phần tử trong RecyclerView hiện thị, có thể sử dụng các lớp kế thừa LinearLayoutManager, GridLayoutManager
  3. RecyclerView.ItemAnimator Lớp để xây dựng cách thực hoạt hình (động) cho các sự kiện trên phần tử hiện thị, như hiệu ứng khi thêm phần tử vào, xóa phần tử khỏi RecyclerView
  4. RecyclerView.Viewholder lớp dùng để gán / cập nhật dữ liệu vào các phần tử.
Mô tả như hình dưới.

2. Sự khác nhau giữa ListView và RecyclerView

Như các bạn đã biết RecyclerView là một ViewGroup mới được giới thiệu trong Android L (Android API 21). Đây là một ViewGroup có chức năng tương tự ListView nhưng nó tỏ ra mạnh mẽ, linh hoạt hơn rất nhiều. ListView chỉ hỗ trợ bạn scroll các item trong ListView theo chiều dọc (vertical) mà không hỗ trợ scroll theo chiều ngang (horizontal) . RecyclerView support được tất cả những thứ đó và hơn thế nữa.
Nhắc qua một chút về ListView
ListView là một view group, hiển thị các thành phần (elements) theo một danh sách, có thể cuộn được theo chiều thẳng đứng. ListView là một view quan trọng, nó được sử dụng rộng rãi trong các ứng dụng Android. Mặc dù vậy nhưng so với ListView thì RecyclerView lại có những điểm mạnh mẽ vượt trội hơn
  1. Yêu cầu sử dụng ViewHolder pattern trong Adapter : với listView thì có hoặc không sử dụng ViewHolder để cải thiện hiệu năng nhưng đối với recyclerview thì bắt buộc phải sử dụng ViewHolder để cải thiện hiệu suất. Và mục đích sử dụng ViewHolder để tái sử dụng View nhằm tránh việc tạo View mới và findViewById quá nhiều
  2. ListView chỉ support cho chúng ta danh sách dạng scroll dọc. Nhưng với RecylerView cung cấp cho chúng ta RecyclerView.LayoutManager cho phép Layout các item trong listView theo các kiểu khác nhau (ngang, dọc, dạng grid, dạng staggered grid).
  3. Với ListView việc sử dụng divider không được linh hoạt nhưng với RecylerView có hỗ trợ ItemDecoration cho phép chúng ta draw divider một cách tuỳ thích.
  4. ListView có support các phương thức phương thức setOnItemClickListener và setOnLongItemListener để chọn 1 item trong ListView. Nhưng RecylerView chỉ support một phương thức đó là onItemTouchListener. *** Khi nào chúng ta nên sử dụng ListView** Bất cứ khi nào bạn cần danh sách các mục. Bất cứ khi nào các mục này không giống nhau. Ví dụ, một hàng có thể chứa 3 TextView và hàng còn lại chứa 5 ImageViews. Bất cứ khi nào các phần tử có thể thay đổi trong thời gian chạy, do sự kiện nhấp chuột của người dùng hoặc sự kiện mạng.

3. Ví dụ sử dụng RecyclerView để hiển thị danh sách

3.1 Mô hình biểu diễn dữ liệu
Đầu tiên bạn phải tạo đối tượng dữ liệu và những thuốc tính của đối tượng dữ liệu.
package com.vncoder.listview;

public class Item {
    private String mName;
    private int mImage;

    public Item(String mName, int mImage) {
        this.mName = mName;
        this.mImage = mImage;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public int getmImage() {
        return mImage;
    }

    public void setmImage(int mImage) {
        this.mImage = mImage;
    }
}
3.2 Thêm RecyclerView vào trong layout
Sau khi thêm thự viện vào build.gradle thì các bạn có thể gọi RecyclerView trong layout của mình.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
Sau khi thêm xong.
3.3 Tạo dữ liệu mẫu cho danh sách hiển thị
Trước tiên bạn phải tạo một file XML dùng để hiển thị cho mỗi dòng của danh sách RecyclerView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal"
    android:padding="4dp"
    android:weightSum="4">

    <ImageView
        android:layout_margin="4dp"
        android:padding="4dp"
        android:layout_weight="3"
        android:id="@+id/im_item"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
<TextView
    android:gravity="center"
    android:layout_gravity="center"
    android:layout_margin="4dp"
    android:padding="4dp"
    android:layout_weight="1"
    android:textSize="30dp"
    android:hint="name"
    android:id="@+id/tv_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

</LinearLayout>
3.4 Tạo Adapter RecyclerView 
Tại đây chúng ta sẽ tạo ra Adapter là nơi xử lý dữ liệu và gán data cho RecyclerVIew. Vai trò của Adapter sẽ chuyển đổi một object tại một vị trí trở thành 1 hàng của danh sách sẽ được gắn vào RecyclerView.
Tuy nhiên đối với RecyclerView Adapter sẽ yêu cầu "ViewHolder" object trong đó mô tả và cung cấp quyền truy cập vào tất cả các View trong mỗi item row. Chúng ta sẽ tạo ra một Adapter và holder bên trong ItemAdapter như sau:
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}
Chúng ta đã có một Adapter và ViewHolder, giờ sẽ hoàn thiện nốt Adapter . Đầu tiên tạo ra các biến cho danh sách các Item và truyền chúng qua hàm tạo:
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {

    private ArrayList<Item> listitems;
    private Context context;

    public ItemAdapter(ArrayList<Item> items, Context context) {
        this.listitems = items;
        this.context = context;
    }
Trong Adapter RecyclerView có 3 phương thức quan trọng nhất :
  1. onCreateViewHolder : tạo ra đối tượng ViewHolder, trong nó chứa View hiện thị dữ liệu
  2. onBindViewHolder : chuyển dữ liệu phần tử vào ViewHolder
  3. getItemCount : cho biết số phần tử của dữ liệu
package com.vncoder.listview;


import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.squareup.picasso.Picasso;

import java.util.ArrayList;


public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {

    private ArrayList<Item> listitems;
    private Context context;

    public ItemAdapter(ArrayList<Item> items, Context context) {
        this.listitems = items;
        this.context = context;
    }



    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View itemView = inflater.inflate(R.layout.item,parent,false);
        ViewHolder viewHolder = new ViewHolder(itemView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Item item = listitems.get(position);
        String name =item.getmName();
        Picasso.with(context).load(item.getmImage()).into(holder.im_item);
        holder.tv_name.setText(item.getmName());
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {
        ImageView im_item;
        TextView tv_name;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            im_item = itemView.findViewById(R.id.im_item);
            tv_name = itemView.findViewById(R.id.tv_name);
        }
    }
}
Kết nối với hàm Main.java
package com.vncoder.listview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private Item mitem;
    private ArrayList<Item> listitem;
    private ItemAdapter mitemAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recycler_view);

        listitem = new ArrayList<>();
        data();
        mitemAdapter = new ItemAdapter(listitem,this);
        recyclerView.setAdapter(mitemAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));



    }

    private void data(){
        listitem.add(new Item("item1",R.drawable.react));
        listitem.add(new Item("item2",R.drawable.java));
        listitem.add(new Item("item3",R.drawable.adobe));
        listitem.add(new Item("item4",R.drawable.html));
        listitem.add(new Item("item5",R.drawable.java));
        listitem.add(new Item("item6",R.drawable.studio));
        listitem.add(new Item("item7",R.drawable.adobe));
        listitem.add(new Item("item7",R.drawable.instagram));
        listitem.add(new Item("item8",R.drawable.twitter));
        listitem.add(new Item("item9",R.drawable.soundcloud));
        listitem.add(new Item("item10",R.drawable.studio));
        listitem.add(new Item("item11",R.drawable.html));
        listitem.add(new Item("item12",R.drawable.react));
        listitem.add(new Item("item13",R.drawable.java));
        listitem.add(new Item("item14   ",R.drawable.linkedin));


    }
}
Thành quả :
RecycleView hiển thị theo 2 phong cách khác nhau 
  1. LinearLayoutManager
  2. GridLayoutManager