Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีอัปเดตข้อมูล RecyclerView Adapter

ภาพรวม

ตัวอย่างนี้แสดงวิธีอัปเดตข้อมูลใน RecyclerView.Adapter อย่างถูกต้อง โดยเพิ่มข้อมูลใหม่และเรียก notifyDataSetChanged() หรือเมธอดเฉพาะเจาะจง

ขั้นตอนการสร้าง

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

เปิด Android Studio ไปที่ File → New Project และกรอกข้อมูลที่จำเป็น

ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="wrap_content">
    
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:scrollbars="vertical" />
    
    <TextView
        android:id="@+id/text"
        android:textSize="30sp"
        android:text="Update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp" />
        
</LinearLayout>

ขั้นตอนที่ 3: เขียนโค้ดหลัก (src/MainActivity.java)

package com.example.myapplication;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private CustomAdapter adapter;
    private ArrayList<String> dataList = new ArrayList<>();
    private TextView updateText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        recyclerView = findViewById(R.id.recycler_view);
        updateText = findViewById(R.id.text);
        
        // Setup RecyclerView
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        
        adapter = new CustomAdapter(this, dataList);
        recyclerView.setAdapter(adapter);
        
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        
        // Initial data
        dataList.add("Sairamm");
        dataList.add("Krishna");
        dataList.add("Prasad");
        adapter.notifyDataSetChanged();
        
        // Click to add new item
        updateText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = dataList.size();
                dataList.add("Mammahe " + position);
                
                // วิธีที่ 1: เรียก notifyDataSetChanged() - เรียบง่ายแต่อาจมี performance issue
                // adapter.notifyDataSetChanged();
                
                // วิธีที่ 2: ใช้ notifyItemInserted() - แนะนำ ให้ Animation สวยกว่า
                adapter.notifyItemInserted(position);
            }
        });
    }
}

ขั้นตอนที่ 4: สร้าง Adapter (src/CustomAdapter.java)

package com.example.myapplication;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private Context context;
    private ArrayList<String> dataList;

    public CustomAdapter(Context context, ArrayList<String> dataList) {
        this.context = context;
        this.dataList = dataList;
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(dataList.get(position));
    }

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

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.title);
        }
    }
}

ขั้นตอนที่ 5: Layout สำหรับ Item (res/layout/list_row.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:textSize="30sp"
        android:layout_marginLeft="10dp"
        android:layout_height="wrap_content" />
</LinearLayout>

วิธี Notify ต่างๆ และเมื่อไหร่ควรใช้

เมธอดใช้เมื่อAnimation
notifyDataSetChanged()ข้อมูลเปลี่ยนแปลงมาก หลายตำแหน่ง หรือโครงสร้างเปลี่ยนไม่มี (Default)
notifyItemInserted(pos)เพิ่ม item เดียวมี Animation เข้า
notifyItemRemoved(pos)ลบ item เดียวมี Animation ออก
notifyItemChanged(pos)อัปเดต item เดียวมี Animation เปลี่ยน
notifyItemRangeInserted(start, count)เพิ่มหลาย item ติดกันมี Animation
notifyItemRangeChanged(start, count)อัปเดตช่วงข้อมูลมี Animation
notifyItemMoved(from, to)ย้าย itemมี Animation

แนวทางปฏิบัติที่ดี (Best Practices)

  • ใช้ notifyItemInserted/Removed/Changed แทน notifyDataSetChanged() เพื่อ Animation ที่สมูท
  • ใช้ DiffUtil สำหรับรายการใหญ่ที่อัปเดตครั้งละมาก
  • ใช้ ListAdapter ร่วมกับ DiffUtil สำหรับโค้ดสะอาดกว่า
  • หลีกเลี่ยงการสร้าง ArrayList ใหม่ทุกครั้ง ให้แก้ไข List เดิม

ตัวอย่างใช้ DiffUtil (แนะนำสำหรับรายการใหญ่)

public class MyDiffCallback extends DiffUtil.ItemCallback<String> {
    @Override
    public boolean areItemsTheSame(@NonNull String oldItem, @NonNull String newItem) {
        return oldItem.equals(newItem);
    }
    
    @Override
    public boolean areContentsTheSame(@NonNull String oldItem, @NonNull String newItem) {
        return oldItem.equals(newItem);
    }
}

// ใช้กับ ListAdapter
ListAdapter<String, ViewHolder> adapter = new ListAdapter<>(new MyDiffCallback()) {
    // ... implementation
};

// อัปเดตข้อมูล
adapter.submitList(newDataList); // คำนวณ diff อัตโนมัติ