ภาพรวม
ตัวอย่างนี้แสดงวิธีอัปเดตข้อมูลใน 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 อัตโนมัติ