Android L Developer Preview : ทดลองเล่น RecyclerView

Android L Developer Preview : ทดลองเล่น RecyclerView Cover Image

Image Cover: http://googledevelopers.blogspot.com/

หลักจากงาน Google I/O 2014 เมื่อวานนั้น Google ได้ทำการเปิดตัว Android L Developer Preview ซึ่งไอ้เจ้า Android L นั้นมันนำการออกแบบสไตล์ที่เรียกกันว่า Material Design มาใช้ หากอยากรู้เกี่ยวกับ Material Design มากขึ้น ก็ เปิดวาร์ปนี้เลยครับ

Material Design

ในส่วนของ Android L Preview มันก็มีส่วน UI Widget ตัวนึงที่น่าสนใจไม่น้อย นั้นก็คือ RecyclerView แล้ว RecyclerView มันคืออะไรล่ะ? แล้วใช้ทำอะไร?

RecyclerView คืออะไร?

คำอธิบายจากเว็บไซต์เลย อธิบายว่า

The new RecyclerView widget is a more advanced version of ListView that provides performance improvements for dynamic views and is easier to use

หรือมันก็คือ ListView ฉบับปรับปรุง เพิ่มประสิทธิภาพ และใช้งานได้ง่ายขึ้นนั้นเอง หลังจากที่ลองเล่นแล้ว ก็พบว่าม้ันมีข้อดีหลายๆอย่างเลย อย่างเช่น

  • มันทำ ListView ได้ทั้งแนวตั้ง แนวนอนเลย
  • มี LayoutManager คอยควบคุม element
  • ใช้ ViewHolder Pattern ซึ่งช่วยในเรื่องการ reuse อย่างมาก
  • เหมาะสำหรับ ListView ที่ข้อมูลมีการเปลี่ยนแปลงบ่อยๆ
  • มี Animation ด้วย (จริงๆ ListView แบบเก่า มันก็ทำได้เหมือนกันนะ)

RecyclerView

จากรูปจะเห็นได้ว่า หากเราจะสร้าง RecyclerView เราต้องมี Adapter และ LayoutManager ฟังดูคุ้นๆมั้ย? มันก็เหมือนกับการสร้าง ListView ธรรมดาน้นแหละ เพียงแต่ว่า เจ้า RecyclerView นั้นมี LayoutManager พ่วงมาด้วย คอยจัดการทุกๆอย่าง เกี่ยวกับข้อมูลใน List ให้ คอยจัดการว่า View ไหนควรจะนำกลับมาใช้ใหม่ หรือแม้แต่การหลีกเลี่ยงการใช้ findViewById ซ้ำๆ ซึ่งมันมีผลต่อ perfomance มากๆ หากข้อมูลมีขนาดใหญ่

ข้อมูลข้างต้น ผมเพียงสรุปจากความเข้าใจ และความเห็นส่วนตัวเท่านั้น หากต้องการอ่านให้ละเอียด แนะนำอ่านจากต้นฉบับดีกว่าครับ ตามนี้เลย UI Widgets: RecyclerView

มาทดลองเล่น RecyclerView กันเลยดีกว่าครับ

เครื่องมือที่ควรมี

  • Android Studio 0.8.0+ หรือ Eclipse/ADT Bundle เวอร์ชั่น 23+
  • Android SDK Tools เวอร์ชั่น 23
  • Android SDK Build-Tools และ Platform-Tools เวอร์ชั่น 20
  • Android L (API 20) และ SDK Platform ของ Android L Preview

Create Project

เริ่มแรก ทำการสร้างโปรเจ็คขึ้นมาเลยครับ แล้วก็สร้างโปรเจ็คตามรูปเลย

RecyclerView1

RecyclerView2

RecyclerView3

RecyclerView4

เมื่อสร้างโปรเจ็คเสร็จ เราจำเป็นต้องเพิ่ม dependencies ในไฟล์ build.gradle ของ module ครับ เปิดไฟล์ขึ้นมา เพิ่มนี้ลงไป เป็นแบบนี้

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "com.android.support:recyclerview-v7:+"
}

จากนั้นกด Sync Project เป็นอันเรียบร้อย สามารถใช้ widget RecyclerView ได้แล้ว ไฟล์ build.gradle สุดท้ายจะเป็นแบบนี้

apply plugin: 'com.android.application'

android {
    compileSdkVersion 'android-L'
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.devahoy.hellorecyclerview"
        minSdkVersion 15
        targetSdkVersion 'L'
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "com.android.support:recyclerview-v7:+"
}

CustomAdapter

ทำการสร้าง CustomAdapter กันก่อน โดยต้องทำการ extends คลาส RecyclerView.Adapter แบบนี้

package com.devahoy.hellorecyclerview;

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;

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

    private List<Player> mPlayers;
    private Context mContext;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mName;
        public TextView mClub;

        public ViewHolder(View view) {
            super(view);

            mName = (TextView) view.findViewById(R.id.name);
            mClub = (TextView) view.findViewById(R.id.club);
        }
    }

    public CustomAdapter(Context context, List<Player> dataset) {
        mPlayers = dataset;
        mContext = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(mContext)
                .inflate(R.layout.recycler_view_row, parent, false);

        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        Player player = mPlayers.get(position);

        viewHolder.mName.setText(player.getName());
        viewHolder.mClub.setText(player.getClub());
    }

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

เมธอดที่สำคัญที่เราทำการ override มีด้วยกันดังนี้

  • onCreateViewHolder() : สำหรับสร้าง ViewHolder ถูกเรียกโดย LayoutManager มันเหมือนกับตอนเราสร้าง ListView แล้วใช้วิธีเช็คว่า View เป็น null หรือไม่ ถ้าเป็น ก็ให้สั่งเชื่อม/ผูก View โดย findViewBydId()

  • onBindViewHolder() : เมธอดนี้ก็ถูกเรียกโดย LayoutManager เหมือนกัน เอาไว้สำหรับ เซทค่า dataset ของเรา ใส่ไปยังพวก View ต่างๆ เช่นใส่ค่าให้ TextView, ImageView

  • getItemCount() : ส่งค่าจำนวน item ของ dataset

จากเมธอด ด้านบน เราจะเห็นว่า มันเหมือนการใช้ ViewHolder Pattern แบบที่เราเคยทำเลย โดยที่เราไม่ต้องมาเช็คว่า View มันเป็น null รึเปล่า เราแค่ เชื่ิอม View กับ View ใน xml ในเมธอด onCreateViewHolder() และเซทค่า content ใน onBindViewHolder() ก็พอ

โค๊ดด้านบน ปล่อยให้ error ก่อนเนื่องจากเรายังไม่มีคลาส Player และเลเอาท์ชื่อ recycler_view.xml

สร้างโมเดล Player

ขั้นตอนนี้ ผมต้องการให้แสดงชื่อนักฟุตบอล และสโมสรที่สังกัด เพราะฉะนั้น ก็เลยสร้าง class ง่ายๆแบบนี้

package com.devahoy.hellorecyclerview;

public class Player {
    private String name;
    private String club;

    public Player(String name, String club) {
        this.name = name;
        this.club = club;
    }

    public String getName() {
        return name;
    }

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

    public String getClub() {
        return club;
    }

    public void setClub(String club) {
        this.club = club;
    }
}

ส่วนไฟล์ recycler_view_row.xml ก็ไม่มีอะไรมาก มีแค่ TextView 2 อัน ไฟล์ก็จะเป็นแบบนี้

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
        android:id="@+id/name"
        android:textColor="#ffee1789"
        android:layout_marginRight="48dp" />

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textColor="#ff0071ff"
              android:id="@+id/club" />
</LinearLayout>

MyActivity

ต่อมา มาที่คลาส MyActivity ที่ส่วน onCreate() ก็ทำแบบนี้เลย

public class MyActivity extends Activity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new CustomAdapter(this, initPlayer());
        mRecyclerView.setAdapter(mAdapter);
    }
}

จากด้านบน คือ ผูก RecyclerView กับ id ในไฟล์ activity_my.xml (ยังไม่ได้สร้าง) แล้วก็ทำการสร้าง LayoutManager ขึ้นมาใหม่ จากนั้น setAdapter โดยใช้ CustomAdapter ที่เราได้สร้างก่อนหน้านี้แล้ว

ต่อมาเพิ่มเมธอด initPlayer() อันนี้เอาไว้สร้างข้อมูลขึ้นมา ตรงนี้ขี้เกียจพิมพ์ ก็เลยใส่ไป 4-5 items

private List<Player> initPlayer() {

    Player messi = new Player("Leonel Missi", "Barcelona");
    Player ronaldo = new Player("Cristiano Ronaldo", "Real Madrid");
    Player suarez = new Player("Luis Suarez", "Liverpool");

    List<Player> dataset = new ArrayList<Player>();

    dataset.add(messi);
    dataset.add(ronaldo);
    dataset.add(suarez);

    return dataset;
}

สุดท้ายสร้างไฟล์ activity_my.xml โดยใช้ widget ชื่อ android.support.v7.widget.RecyclerView

<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"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MyActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

ทดสอบรันโปรแกรมดูครับ (AVD ต้องสร้างด้วย Android L นะครับ ใครสร้างไม่เป็น ก็นี้เลย Setup SDK )

อ้อ ตัว RecyclerView มันรองรับ Support Library ด้วยนะ ผมยังไม่ได้เทสเท่าไหร่ หากใครเทสหรือลองเล่นแล้ว ก็มาแชร์กันได้นะครับ

สรุป

RecyclerView ส่วนตัวคิดว่า มันก็น่าสนใจดีครับ ตามสไตล์ของ Material Design ต้องรอดูต่อไปว่า อนาคตมันจะเป็นเช่นไร เนื่องจากตอนนี้ยังไม่มีข้อมูลอะไรมาก รายละเอียดก็น้อย บางทีก็บัคกระจายเลย สำหรับใครสนใจเพิ่มเติม ก็ลองไปอ่านต้นฉบับดู น่าจะรู้เรื่องกว่าอ่านที่นี่นะครับ :D

Chai

Chai Phonbopit : Developer แห่งหนึ่ง • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Node.js, JavaScript และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด