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

วิธีใช้ Comparator Interface สำหรับ ListView บน Android

การเรียงลำดับ ListView ด้วย Comparator Interface บน Android

ตัวอย่างนี้สาธิตการใช้ Comparator<T> interface เพื่อกำหนดกฎการเรียงลำดับ (Sorting) แบบกำหนดเอง สำหรับข้อมูลใน ArrayList ก่อนแสดงใน ListView

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

สร้างโปรเจกต์ Android ใหม่ใน Android Studio

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ป้อนชื่อ" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">
        <Button android:id="@+id/btnSave" android:text="บันทึก" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnRefresh" android:text="รีเฟรช" android:layout_width="wrap_content" android:layout_height="wrap_content" />
    </LinearLayout>

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp">
    </ListView>
</LinearLayout>

ขั้นตอนที่ 3: MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;

public class MainActivity extends AppCompatActivity {
    private EditText etName;
    private ListView listView;
    private ArrayAdapter<String> adapter;
    private ArrayList<String> arrayList = new ArrayList<>();
    private Set<String> uniqueSet = new HashSet<>();

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

        etName = findViewById(R.id.etName);
        listView = findViewById(R.id.listView);

        findViewById(R.id.btnRefresh).setOnClickListener(v -> {
            if (adapter != null) {
                adapter.notifyDataSetChanged();
                listView.invalidateViews();
                listView.refreshDrawableState();
            }
        });

        findViewById(R.id.btnSave).setOnClickListener(v -> {
            String input = etName.getText().toString().trim();
            if (!input.isEmpty()) {
                uniqueSet.add(input);
                arrayList.clear();
                arrayList.addAll(uniqueSet);

                // จุดสำคัญ: ใช้ Collections.sort() พร้อม Comparator แบบ Anonymous Class
                Collections.sort(arrayList, new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        // เรียงตามตัวอักษร A-Z (Natural Order)
                        return o1.compareTo(o2);
                    }
                });

                adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
                listView.setAdapter(adapter);

                Toast.makeText(this, "บันทึกสำเร็จ (เรียง A-Z)", Toast.LENGTH_SHORT).show();
            } else {
                etName.setError("กรุณาป้อนชื่อ");
            }
        });
    }
}

คำอธิบาย Comparator Interface

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}
  • compare(o1, o2) คืนค่า:
    • < 0 : o1 น้อยกว่า o2 (o1 อยู่ก่อน)
    • = 0 : o1 เท่ากับ o2
    • > 0 : o1 มากกว่า o2 (o1 อยู่หลัง)
  • เป็น Functional Interface → ใช้ Lambda Expression ได้ (Java 8+)
  • แยก Logic การเรียงจาก Object เอง (Separation of concerns)

ตัวอย่าง Comparator แบบต่างๆ

1. เรียงตามตัวอักษร A-Z (Natural Order) - ตัวอย่างพื้นฐาน

Collections.sort(list, (s1, s2) -> s1.compareTo(s2));
// หรือ
Collections.sort(list); // String implements Comparable

2. เรียงตามตัวอักษร Z-A (Descending)

Collections.sort(list, (s1, s2) -> s2.compareTo(s1));
// หรือ
Collections.sort(list, Comparator.reverseOrder());

3. เรียงตามความยาวสตริง (สั้นไปยาว)

Collections.sort(list, (s1, s2) -> Integer.compare(s1.length(), s2.length()));

4. เรียงตามความยาวสตริง (ยาวไปสั้น)

Collections.sort(list, (s1, s2) -> Integer.compare(s2.length(), s1.length()));

5. เรียงแบบหลายเงื่อนไข (Multi-level Sort)

// 1. เรียงตามความยาว (สั้นไปยาว) 2. ถ้ายาวเท่ากัน เรียง A-Z
Collections.sort(list, Comparator
    .comparingInt(String::length)
    .thenComparing(Comparator.naturalOrder()));

6. เรียงแบบ Case-Insensitive

Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
// หรือ
Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2));

7. เรียง Object แบบกำหนดเอง (Custom Object)

// สมมติมี class Person { String name; int age; }
List<Person> people = ...;

// เรียงตามอายุ น้อยไปมาก
Collections.sort(people, (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));

// เรียงตามชื่อ แล้วค่อยอายุ
Collections.sort(people, Comparator
    .comparing(Person::getName)
    .thenComparingInt(Person::getAge));

8. ใช้ Method Reference (Java 8+)

// Static method
Comparator<String> cmp = String::compareToIgnoreCase;

// Instance method
Comparator<String> cmp = String::compareTo;

// Constructor reference (สำหรับสร้าง Object)

ตัวอย่างการทำงาน (Input: D, A, E, B, C)

Comparatorผลลัพธ์
Natural (A-Z)A, B, C, D, E
Reverse (Z-A)E, D, C, B, A
Length ASCA, B, C, D, E (ทั้งหมดยาว 1)
Length DESCE, D, C, B, A
Case Insensitivea, B, c, D, e (ถ้ามี mixed case)

Comparator vs Comparable

FeatureComparable<T>Comparator<T>
Interfacejava.lang.Comparablejava.util.Comparator
MethodcompareTo(T other)compare(T o1, T o2)
Locationภายใน Class (this vs other)ภายนอก Class (o1 vs o2)
Multiple Ordersไม่ได้ (มีเพียง 1 natural order)ได้ไม่จำกัด (หลาย Comparator)
Modify Existing Classต้องแก้ Classไม่ต้องแก้ Class
Use CaseDefault/Natural SortingCustom/Specific Sorting

Java 8+ Comparator Factory Methods

// Static factory methods
Comparator.naturalOrder()           // Natural order (nulls first)
Comparator.reverseOrder()           // Reverse natural order
Comparator.nullsFirst(cmp)          // Nulls first, then cmp
Comparator.nullsLast(cmp)           // cmp first, then nulls last
Comparator.comparing(Function)      // Key extractor
Comparator.comparingInt(ToIntFunction)
Comparator.comparingLong(ToLongFunction)
Comparator.comparingDouble(ToDoubleFunction)
Comparator.thenComparing(Function)  // Chain comparators

กรณีการใช้งานจริง

  • รายชื่อติดต่อ: เรียงตามชื่อ, นามสกุล, บริษัท
  • รายการสินค้า: เรียงตามราคา, คะแนน, ยอดขาย, วันที่เพิ่ม
  • Leaderboard: เรียงคะแนนสูง-ต่ำ, เวลาเร็ว-ช้า
  • Log/Event: เรียงตาม Timestamp, Severity, Source
  • File Explorer: เรียงตามชื่อ, ขนาด, วันที่แก้ไข, ประเภท

Best Practices

  • ใช้ Comparator.comparing() + thenComparing() สำหรับ Multi-field sorting
  • หลีกเลี่ยงการสร้าง Object ใหม่ใน compare() (Performance)
  • ใช้ Comparator.nullsFirst/Last() จัดการ null อย่างชัดเจน
  • ทำให้ Comparator เป็น Consistent with equals() (แนะนำ)
  • Document sorting logic ให้ชัดเจน