ภาพรวม
ตัวอย่างนี้สาธิตการใช้ TextToSpeech (TTS) ผ่าน Singleton Pattern เพื่อจัดการ Engine TTS แบบรวมศูนย์ หลีกเลี่ยงการสร้าง Engine ซ้ำซ้อน และจัดการ Lifecycle ให้ถูกต้อง
ขั้นตอนการสร้าง
ขั้นตอนที่ 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">
<EditText
android:id="@+id/editText"
android:hint="พิมพ์ข้อความที่ต้องการให้พูด"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/show"
android:text="TTS จาก Singleton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
ขั้นตอนที่ 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;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
Button show;
SingleTonExample singletonExample;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = findViewById(R.id.show);
singletonExample = SingleTonExample.getInstance();
singletonExample.init(getApplicationContext());
final EditText editText = findViewById(R.id.editText);
show.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = editText.getText().toString().trim();
if (!text.isEmpty()) {
singletonExample.textToSpeech(text);
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
singletonExample.shutdown(); // สำคัญ: ปิด TTS Engine
}
}
ขั้นตอนที่ 4: สร้างคลาส Singleton (SingleTonExample.java)
package com.example.andy.myapplication;
import android.content.Context;
import android.speech.tts.TextToSpeech;
import java.util.Locale;
public class SingleTonExample {
private TextToSpeech tts;
private static SingleTonExample ourInstance = new SingleTonExample();
private Context appContext;
private SingleTonExample() { }
public static synchronized SingleTonExample getInstance() {
return ourInstance;
}
public void init(Context context) {
if (appContext == null) {
this.appContext = context;
// เริ่มต้น TTS Engine ครั้งเดียว
tts = new TextToSpeech(context, status -> {
if (status != TextToSpeech.ERROR) {
tts.setLanguage(Locale.UK); // หรือ Locale.getDefault()
}
});
}
}
public void textToSpeech(String text) {
if (tts != null) {
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, "utteranceId");
}
}
public void shutdown() {
if (tts != null) {
tts.stop();
tts.shutdown();
tts = null;
}
}
public boolean isLanguageAvailable(Locale locale) {
return tts != null && tts.isLanguageAvailable(locale) >= TextToSpeech.LANG_AVAILABLE;
}
}
การทดสอบ
รันแอปพลิเคชัน ป้อนข้อความใน EditText แล้วกดปุ่ม

ระบบจะเล่นเสียงพูดข้อความที่ป้อนจาก Singleton Class
ปัญหาของโค้ดต้นฉบับและการแก้ไข
| ปัญหา | การแก้ไข |
|---|---|
| สร้าง TTS Engine ใหม่ทุกครั้งที่เรียก speak() | ย้าย initialization ไปที่ init() ครั้งเดียว |
| ไม่มีการ shutdown TTS | เพิ่มเมธอด shutdown() เรียกใน onDestroy() |
| ใช้ get() ที่คืนค่า Context แทนการส่ง Context เข้าไป | ส่ง Context ผ่าน init() โดยตรง |
| ไม่ตรวจสอบสถานะ initialization | เพิ่ม callback OnInitListener |
แนวทางปฏิบัติที่ดีกว่า (Modern Kotlin + Coroutines)
// TTS Manager with Kotlin Coroutines
class TtsManager(private val context: Context) {
private var tts: TextToSpeech? = null
private val initMutex = Mutex()
suspend fun speak(text: String, locale: Locale = Locale.getDefault()) {
awaitInitialization()
tts?.speak(text, TextToSpeech.QUEUE_FLUSH, null, "id")
}
private suspend fun awaitInitialization() {
initMutex.withLock {
if (tts == null) {
tts = TextToSpeech(context, status -> { })
// รอ initialization ด้วย suspendCancellableCoroutine
}
}
}
fun shutdown() {
tts?.apply { stop(); shutdown() }
tts = null
}
}
// Usage with Hilt
@Singleton
class TtsManager @Inject constructor(@ApplicationContext context: Context) : TtsManager(context)
สิทธิ์ที่จำเป็น (Permissions)
ไม่ต้องการ Permission พิเศษ แต่ควรตรวจสอบว่า裝置รองรับ TTS Engine และภาษาที่ต้องการ
สรุป
Singleton TTS ช่วยจัดการ Engine ให้มีเพียงตัวเดียว ลด Resource Usage และป้องกัน Memory Leak จุดสำคัญคือการ Initialize ครั้งเดียว และ Shutdown อย่างถูกต้องเมื่อไม่ใช้งาน