TextToSpeech Singleton Pattern
TextToSpeech (TTS) engine tốn tài nguyên khởi tạo. Sử dụng Singleton đảm bảo chỉ tạo một instance TTS trong suốt vòng đời ứng dụng, tránh lag khi phát âm thanh liên tục.
Bước 1: Tạo dự án
Android Studio → File → New Project.
Bước 2: Giao diện (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/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nhập nội dung cần đọc"
android:inputType="textMultiLine"
android:minHeight="100dp" />
<Button
android:id="@+id/show"
android:text="Phát âm thanh từ Singleton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp" />
</LinearLayout>
Bước 3: MainActivity.java
package com.example.ttssingleton;
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 btnSpeak;
EditText editText;
TtsSingleton ttsSingleton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSpeak = findViewById(R.id.show);
editText = findViewById(R.id.editText);
ttsSingleton = TtsSingleton.getInstance();
ttsSingleton.init(getApplicationContext());
btnSpeak.setOnClickListener(v -> {
String text = editText.getText().toString().trim();
if (!text.isEmpty()) {
ttsSingleton.speak(text);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
ttsSingleton.shutdown(); // Quan trọng: giải phóng TTS engine
}
}
Bước 4: TtsSingleton.java
package com.example.ttssingleton;
import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.widget.Toast;
import java.util.Locale;
public class TtsSingleton {
private TextToSpeech tts;
private Context appContext;
private boolean isInitialized = false;
private static final TtsSingleton ourInstance = new TtsSingleton();
public static synchronized TtsSingleton getInstance() {
return ourInstance;
}
private TtsSingleton() { }
public void init(Context context) {
if (appContext == null) {
this.appContext = context.getApplicationContext();
tts = new TextToSpeech(appContext, status -> {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
// Ngôn ngữ không hỗ trợ
} else {
isInitialized = true;
}
}
});
}
}
public void speak(String text) {
if (tts != null && isInitialized) {
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, "utteranceId");
}
}
public void shutdown() {
if (tts != null) {
tts.stop();
tts.shutdown();
tts = null;
isInitialized = false;
}
}
public boolean isReady() {
return isInitialized;
}
}
Chạy ứng dụng
Nhập văn bản → nhấn nút → nghe giọng đọc. Thử xoay màn hình, văn bản vẫn được đọc đúng vì Singleton giữ instance TTS.
⚠️ Các vấn đề cần lưu ý
- Phải gọi shutdown() trong onDestroy() để tránh memory leak TTS engine.
- Khởi tạo bất đồng bộ: TTS cần thời gian init, nên kiểm tra
isInitializedtrước khi speak. - Ngôn ngữ: Kiểm tra setLanguage() trả về SUCCESS trước khi dùng.
- API 21+: Nên dùng
speak(text, QUEUE_FLUSH, null, utteranceId)thay vì phiên bản cũ.
Cải tiến: Hỗ trợ callback khi nói xong
public void speak(String text, UtteranceProgressListener listener) {
if (tts != null && isInitialized) {
tts.setOnUtteranceProgressListener(listener);
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "myId");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, params, "myId");
}
}