Sử Dụng RecyclerView trong Android — Android

Trước khi tìm hiểu RecyclerView nên đọc lại 3 bài viết về ListView từ cơ bản tới nâng cao:

RecyclerView so với ListView

So với ListView thì RecyclerView có những điểm mạnh mẽ vượt trội hơn như sau:

  • ListView không cần sử dụng ViewHolder pattern để cải thiện hiệu suất của ListView. Nhưng ngược lại, khi tạo 1 Adapter sử dụng với RecyclerView, bắt buộc phải sử dụng ViewHolder để cải thiện hiệu suất.
  • 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.
  • ListView chỉ hỗ trợ danh sách dạng cuộn dọc, RecylerView cung cấp RecyclerView.LayoutManager cho phép layout các item trong ListView theo các kiểu khác nhau (ngang, dọc, dạng lưới, dạng staggered grid).
  • Xử lý animation cho các item trong ListView không dễ dàng nhưng RecyclerView có hỗ trợ ItemAnimator giúp xử lý animation khi thêm vào hay xóa 1 item ra khỏi Recycler 1 cách dễ dàng. Mặc định RecyclerView, sử dụng DefaultItemAnimator.
  • ListView sử dụng divider không được linh hoạt nhưng với RecylerView có hỗ trợ ItemDecoration, cho phép vẽ divider 1 cách tùy thích.
  • ListView hỗ trợ các phương thức setOnItemClickListener()setOnLongItemListener() để chọn 1 item trong ListViewRecylerView chỉ hỗ trợ 1 phương thức onItemTouchListener().

Các thành phần khi sử dụng RecyclerView

Khi sử dụng RecyclerView phải làm việc với những thành phần sau đây:

RecyclerView.Adapter

Đây là thành phần xử lý dữ liệu collecion (dữ liệu kiểu danh sách) và bind (gắn) những dữ liệu này, lên các item của RecyclerView.

Khi tạo custom Adapter phải override lại 2 phương thức chính là:

  • onCreateViewHolder(): dùng để tạo View mới cho RecyclerView, nếu RecyclerView đã cached lại View thì phương thức này sẽ không được gọi.
  • onBindViewHolder(): dùng gắn dữ liệu vào View.

LayoutManager

Là thành phần có chức năng sắp xếp các item trong RecylerView. Các item cuộn dọc hay ngang đều phụ thuộc vào đặt LayoutManager cho RecyclerView.

Các lớp con của LayoutManager:

  • LinearLayoutManager: hỗ trợ cuộn các item theo chiều ngang hay chiều dọc.
  • GridLayoutManager: layout các item trong RecyclerView dưới dạng Grid giống như khi sử dụng GridView.
  • StaggerdGridLayoutManager: layout các item trong ListView dưới dạng lưới so le.

ItemAnimator: là thành phần hỗ trợ animation khi thêm vào hay xóa 1 item ra khỏi RecyclerView. Để tìm hiểu rõ phần này, cần tìm hiểu các lớp sau:

  • ItemAnimator: là lớp đại diện cho khung sườn của animation trong RecyclerView.
  • SimpleItemAnimator: là lớp wrapper lại ItemAnimator.
  • DefaultItemAnimator: lớp xử lý animation mặc định sử dụng trong RecyclerView.

Sử dụng RecyclerView trong Android

Mặc định RecyclerView không có sẵn trong Android SDK mà phải import vào thư viện. Chỉ cần dán dòng dưới đây vào build.gradle của module app, sau đó nhấn Sync Now để Android Studio tải và nạp thư viện tự động.

compile 'com.android.support:recyclerview-v7:23.0.0'

Hoặc cách khác là vào FileProject Structure, chọn module app và chuyển sang tab Dependencies, sau đó nhấn vào dấu + và chọn Library Dependencies.

Tìm thư viện RecyclerView, sau đó nhấn OK để import thư viện:

Sau khi đã import thư viện, bắt đầu tìm hiểu cách sử dụng RecyclerView như sau:

  1. Tạo model lớp để chứa dữ liệu.
  2. Thêm RecyclerView vào main_activity.xml.
  3. Tạo giao diện cho 1 dòng.
  4. Tạo custom Adapter và gán dữ liệu cho từng dòng trong Adapter.
  5. Cài đặt RecyclerView trong MainActivity.java.

Bước 1: tạo model để chứa dữ liệu

Lớp Song đại diện cho 1 bài hát, gồm các thông tin:

  • mCode: mã số bài hát.
  • mTitle: tên bài hát.
  • mLyric: lời của bài hát.
  • mAstist: tên ca sĩ.

File Song.java

package com.eitguide.nguyennghia.recyclerviewandroid;
/**
 * Created by nguyennghia on 8/25/16.
 */
public class Song {
    private String mCode;
    private String mTitle;
    private String mLyric;
  private String mArtist;
    public Song() {
      // TODO something
    }

    public Song(String code, String title, String lyric, String artist) {
        this.mCode = code;
        this.mTitle = title;
        this.mLyric = lyric;
        this.mArtist = artist;
    }

    public String getCode() {
        return mCode;
    }

    public String getTitle() {
        return mTitle;
    }

    public String getLyric() {
        return mLyric;
    }

    public String getArtist() {
        return mArtist;
    }

    public void setCode(String code) {
        this.mCode = code;
    }

    public void setTitle(String title) {
        this.mTitle = title;
    }

    public void setLyric(String lyric) {
        this.mLyric = lyric;
    }

    public void setArtist(String artist) {
        this.mArtist = artist;
    }
}

Bước 2: thêm RecyclerView vào main_activity.xml

File main_activity.java

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  tools:context="com.eitguide.nguyennghia.recyclerviewandroid.MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_songs"
        android:layout_width="match_parent"
      android:layout_height="match_parent"/>
</RelativeLayout>

Bước 3: tạo giao diện cho 1 row

File row_item_song.xml trong thư mục layout của project, được thiết kế để hiển thị dòng như hình dưới đây:

Và mã nguồn của file này:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="3dp"
    android:paddingLeft="6dp"
    android:paddingRight="6dp"
  android:paddingTop="3dp">
    <FrameLayout
        android:id="@+id/fl_code"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
      android:layout_centerVertical="true">
        <TextView
            android:id="@+id/tv_code"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#19b395"
            android:textSize="18dp" />
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_toRightOf="@+id/fl_code"
      android:orientation="vertical">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:textColor="#2c3e50"
            android:textSize="16dp"
          android:textStyle="bold" />
        <TextView
            android:id="@+id/tv_lyric"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:textColor="#34495e"
          android:textSize="14dp" />
        <TextView
            android:id="@+id/tv_artist"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7f8c8d"
          android:textSize="14dp" />
    </LinearLayout>
</RelativeLayout>

Bước 4: tạo custom Adapter và gắn dữ liệu cho từng dòng trong Adapter

package com.eitguide.nguyennghia.recyclerviewandroid;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/**
 * Created by nguyennghia on 8/25/16.
*/
public class SongAdapter extends RecyclerView.Adapter<SongAdapter.SongViewHolder> {
    private static final String TAG = "SongAdapter";
    private List<Song> mSongs;
    private Context mContext;
  private LayoutInflater mLayoutInflater;

    public SongAdapter(Context context, List<Song> datas) {
        mContext = context;
        mSongs = datas;
        mLayoutInflater = LayoutInflater.from(context);
  }

    @Override
    public SongViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      // Inflate view from row_item_song.xml
        View itemView = mLayoutInflater.inflate(R.layout.row_item_song, parent, false);
        return new SongViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(SongViewHolder holder, int position) {
      // Get song in mSong via position
        Song song = mSongs.get(position);

        //bind data to viewholder
        holder.tvCode.setText(song.getCode());
        holder.tvTitle.setText(song.getTitle());
        holder.tvLyric.setText(song.getLyric());
        holder.tvArtist.setText(song.getArtist());
    }

    @Override
    public int getItemCount() {
        return mSongs.size();
    }
    
    class SongViewHolder extends RecyclerView.ViewHolder {
        private TextView tvCode;
        private TextView tvTitle;
        private TextView tvLyric;
        private TextView tvArtist;

        public SongViewHolder(View itemView) {
            super(itemView);
            tvCode = (TextView) itemView.findViewById(R.id.tv_code);
            tvTitle = (TextView) itemView.findViewById(R.id.tv_title);
            tvLyric = (TextView) itemView.findViewById(R.id.tv_lyric);
            tvArtist = (TextView) itemView.findViewById(R.id.tv_artist);
        }
    }
}

Tạo Custom Adapter trong RecyclerView dễ dàng hơn so với ListView, chỉ cần tạo 1 lớp kế thừa RecyclerView. Còn ViewHolder chỉ việc xử lý trong onCreateViewHolder để tạo mới ViewHolder. Và onBindViewHolder để gán dữ liệu lấy từ collection vào ViewHolder.

Bước 5: cài đặt RecyclerView trong MainActivity.java

Không giống như ListView chỉ cần đặt Adapter cho ListView là đủ. Đối với RecyclerView phải đặt 2 thành phần bắt buộc dưới đây:

  • Đặt adapter cho RecyclerView sử dụng phương thức setAdapter().
  • Đặt layout manager để muốn layout các item như các kiểu dọc, ngang, lưới, lưới so le bằng cách sử dụng phương thức setLayoutManager().

Mã nguồn MainActivity.java

package com.eitguide.nguyennghia.recyclerviewandroid;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView rvSongs;
    private SongAdapter mSongAdapter;
    private List<Song> mSongs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      rvSongs = (RecyclerView)findViewById(R.id.rv_songs);
      // Create song data
        mSongs = new ArrayList<>();
        mSongs = new ArrayList<>();
        mSongs.add(new Song("60696", "NẾU EM CÒN TỒN TẠI", "Khi anh bắt đầu 1 tình yêu Là lúc anh tự thay", "Trịnh Đình Quang"));
        mSongs.add(new Song("60701", "NGỐC", "Có rất nhiều những câu chuyện Em dấu riêng mình em biết", "Khắc Việt"));
        mSongs.add(new Song("60650", "HÃY TIN ANH LẦN NỮA", "Dẫu cho ta đã sai khi ở bên nhau Cô yêu thương", "Thiên Dũng"));
        mSongs.add(new Song("60610", "CHUỖI NGÀY VẮNG EM", "Từ khi em bước ra đi cõi lòng anh ngập tràng bao", "Duy Cường"));
        mSongs.add(new Song("60656", "KHI NGƯỜI MÌNH YÊU KHÓC", "Nước mắt em đang rơi trên những ngón tay Nước mắt em", "Phạm Mạnh Quỳnh"));
        mSongs.add(new Song("60685", "MỞ", "Anh mơ gặp em anh mơ được ôm anh mơ được gần", "Trịnh Thăng Bình"));
        mSongs.add(new Song("60752", "TÌNH YÊU CHẮP VÁ", "Muốn đi xa nơi yêu thương mình từng có Để không nghe", "Mr. Siro"));
        mSongs.add(new Song("60608", "CHỜ NGÀY MƯA TAN", "1 ngày mưa và em khuất xa nơi anh bóng dáng cứ", "Trung Đức"));
        mSongs.add(new Song("60603", "CÂU HỎI EM CHƯA TRẢ LỜI", "Cần nơi em 1 lời giải thích thật lòng Đừng lặng im", "Yuki Huy Nam"));
        mSongs.add(new Song("60720", "QUA ĐI LẶNG LẼ", "Đôi khi đến với nhau yêu thương chẳng được lâu nhưng khi", "Phan Mạnh Quỳnh"));
      mSongs.add(new Song("60856", "QUÊN ANH LÀ ĐIỀU EM KHÔNG THỂ - REMIX", "Cần thêm bao lâu để em quên đi niềm đâu Cần thêm", "Thiện Ngôn"));
        mSongAdapter = new SongAdapter(this,  mSongs);
      rvSongs.setAdapter(mSongAdapter);
        RecyclerView scroll vertical
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        rvSongs.setLayoutManager(linearLayoutManager);
    }
}

Chú ý đoạn mã:

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

Vì muốn RecyclerView cuộn theo chiều dọc nên sử dụng LinearLayoutManager.VERTICAL. Nếu muốn cuộn theo chiều ngang thì truyền vào LinearLayoutManager.HORIZONTAL:

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);

Sử dụng những lớp sau để setLayoutManager() cho RecyclerView:

  • GridLayoutManager: layout các item trong RecyclerView theo dạng lưới.
  • StaggeredLayoutManager: layout các item trong RecyclerView theo dạng lưới so le nhau.

Select item trong RecyclerView

Chọn item trong RecyclerView, bằng cách setOnClickListenner cho itemView, trong constructor của ViewHolder như sau:

class SongViewHolder extends RecyclerView.ViewHolder {
   private TextView tvCode;
   private TextView tvTitle;
   private TextView tvLyric;
   private TextView tvArtist;
   public SongViewHolder(View itemView) {
      super(itemView);
      tvCode = (TextView) itemView.findViewById(R.id.tv_code);
      tvTitle = (TextView) itemView.findViewById(R.id.tv_title);
      tvLyric = (TextView) itemView.findViewById(R.id.tv_lyric);
      tvArtist = (TextView) itemView.findViewById(R.id.tv_artist);
      itemView.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Song song = mSongs.get(getAdapterPosition());
              Toast.makeText(mContext, song.getTitle(), Toast.LENGTH_SHORT).show();
           }
       });
   }
}

Tải code sử dụng trong bài viết:

  • Tải trực tiếp tại: RecyclerViewAndroid-master.zip.
  • Tải thông qua Github.

Bài chung series