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

วิธีใช้ Android Text-to-Speech (TTS) จาก Singleton

ภาพรวม

ตัวอย่างนี้สาธิตการใช้ 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 แล้วกดปุ่ม

วิธีใช้ Android Text-to-Speech (TTS) จาก Singleton

ระบบจะเล่นเสียงพูดข้อความที่ป้อนจาก 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 อย่างถูกต้องเมื่อไม่ใช้งาน