ภาพรวม
Singleton เป็นรูปแบบการออกแบบที่จำกัดการสร้างอินสแตนซ์ของคลาสให้มีเพียงอินสแตนซ์เดียว การใช้ synchronized รับประกันว่าในเวลาเดียวกันจะมีเธรดเดียวเท่านั้นที่เข้าถึงเมธอดได้ ซึ่งเหมาะสำหรับการจัดการ Dialog ที่อาจถูกเรียกจากหลายเธรดพร้อมกัน
ตัวอย่าง: Singleton Dialog แบบ Thread-Safe
ตัวอย่างนี้สาธิตการใช้ Singleton Dialog พร้อม synchronized ใน Android มีปุ่ม 2 ปุ่ม: เริ่ม Dialog และ ปิด Dialog
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
Android Studio → File → New Project → กรอกรายละเอียด
ขั้นตอนที่ 2: จัดรูปแบบหน้าจอ (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">
<Button
android:id="@+id/start"
android:text="เริ่ม Dialog ใน Singleton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/end"
android:text="ปิด Dialog Singleton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
มีปุ่ม 2 ปุ่ม: ปุ่ม Start แสดง Progress Dialog, ปุ่ม End ปิด Progress Dialog
ขั้นตอนที่ 3: เขียนโค้ด MainActivity (src/MainActivity.java)
package com.example.andy.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button start;
SingleTonExample singletonExample;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = findViewById(R.id.start);
singletonExample = SingleTonExample.getInstance();
findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
singletonExample.dismiss();
}
});
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
singletonExample.show(MainActivity.this);
}
});
}
}
ขั้นตอนที่ 4: สร้างคลาส Singleton (SingleTonExample.java)
package com.example.andy.myapplication;
import android.app.Dialog;
import android.content.Context;
import android.view.Window;
public class SingleTonExample {
private Dialog dialog;
private static final SingleTonExample ourInstance = new SingleTonExample();
public static synchronized SingleTonExample getInstance() {
return ourInstance;
}
private SingleTonExample() { }
public void show(Context context) {
if (dialog != null && dialog.isShowing()) {
return; // ป้องกันการเปิด Dialog ซ้ำ
}
dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.layout_progress_dialog);
dialog.setCancelable(true);
dialog.show();
}
public void dismiss() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
}
ขั้นตอนที่ 5: สร้าง Layout สำหรับ Dialog (res/layout/layout_progress_dialog.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="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progress" />
</LinearLayout>
การทดสอบ
รันแอปพลิเคชันบนอุปกรณ์จริง หน้าจอเริ่มต้นจะแสดงตามภาพ

คลิกปุ่ม "เริ่ม Dialog ใน Singleton" จะแสดง Dialog จาก Singleton Class

ข้อดีของการใช้ Synchronized
- ป้องกัน Race Condition เมื่อหลายเธรดพยายามสร้าง/แสดง Dialog พร้อมกัน
- รับประกันว่ามี Dialog แสดงอยู่ได้เพียงอันเดียวในเวลาเดียวกัน
- เหมาะสำหรับ Loading Dialog ที่อาจถูกเรียกจาก Network Callback หลายจุด
แนวทางปฏิบัติที่ดีกว่า (Modern Approach)
ในปัจจุบันแนะนำให้ใช้ DialogFragment หรือ Jetpack Compose Dialog แทน เพราะจัดการ Lifecycle ได้ดีกว่า และรองรับ Configuration Changes (เช่นการหมุนหน้าจอ) อัตโนมัติ