非 activity class/View 适配器 class 中的 TextToSpeech,朗读失败:未绑定到 TTS 引擎
TextToSpeech in non-activity class/View Adapter class, speak failed: not bound to TTS engine
我使用 Tabbed-Fragments 中的 RecyclerView 为我的应用程序开发了一个模块。
场景
使用 RecyclerView 在每个片段中显示了多个动态加载的图像。当用户点击任何图像时,系统会使用 TextToSpeech 说出有关它的一些信息。
当前代码
我正在为 RecyclerView 使用适配器 class,它成功地将图像加载到视图。这是代码:
import android.speech.tts.TextToSpeech;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private ArrayList<CreateList> galleryList;
private Context context;
TextToSpeech tts;
public MyAdapter(Context context, ArrayList<CreateList> galleryList) {
this.galleryList = galleryList;
this.context = context;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
.....
}
@Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
.....
.....
viewHolder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
.....
.....
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
if(status !=TextToSpeech.ERROR){
tts.setLanguage(Locale.UK);
}
}
});
tts.setPitch(pitch);
tts.setSpeechRate(speechRate);
tts.speak(StringToSpeak, TextToSpeech.QUEUE_FLUSH, null);
}
@Override
public int getItemCount() {
return galleryList.size();
}
.....
.....
}
如您所见,我在 viewHolder 上添加了一个 OnClickListener
,它使用 onInitListener
初始化 TTS 对象并朗读信息。但是每当我点击 Fragment 中的任何 image/view/item 时,它什么也说不出来。 LogCat 中没有崩溃,也没有异常,我得到的只是以下消息和其他消息:
I/TextToSpeech: Sucessfully bound to com.google.android.tts
W/TextToSpeech: speak failed: not bound to TTS engine
我尝试调试应用程序并发现在初始化 TTS 对象时 returns engine=Null
在这一行:
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
....});
在扩展 Activity 的其他 class 中,代码和 TTS 工作正常,但在我的 Adapter/Non-Activity class 中它不会启动 TTS,因为它无法绑定到 TTS 引擎。我尝试在我的适配器 class 中使用以下函数实现接口 implements TextToSpeech.OnInitListener
:
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.UK);
}
}
但没有结果 :( 我还尝试创建一个抽象 class 扩展 Activity,在其 OnCreate()
中实现 TTS 并包含一个自定义函数 SpeakMessage()
我尝试在我的适配器 Class 中调用但失败了。我已经花了几个小时试图找出问题及其解决方案,深入研究了 Whosebug 和其他网站上的每个 TTS 相关问题,但找不到任何我的问题的解决方案。请帮助我确定问题及其正确的解决方案。提前致谢。还有一件事,在视图的相同动作侦听器中,使用 MediaPlayer 播放录制的音频消息非常完美。唯一的问题是说出字符串消息使用 TTS。
我成功实现了文字转语音
下面是我的代码
我已经实施了两种方法,一种用于 <20 api,一种用于 >21api
@SuppressWarnings("deprecation")
private void ttsUnder20(String text) {
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, map);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void ttsGreater21(String text) {
String utteranceId = this.hashCode() + "";
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, params, utteranceId);
}
这里是调用这个方法的方法。
private void playNextChunk(String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ttsGreater21(text);
} else {
ttsUnder20(text);
}}
从 onInit 方法调用 playChunk 方法
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
playNextChunk(String text)
}
}
另一个建议文本到语音可以一次说出 4000 个字符,如果您有超过 4000 个字符的字符串,则需要分块播放。为此你需要实现这个监听器 tts.setOnUtteranceProgressListener
试试这个代码,我已经在你的适配器中添加了代码。
public class MyAdapter extends
RecyclerView.Adapter<MyAdapter.ViewHolder>{
private ArrayList<CreateList> galleryList;
private Context context;
TextToSpeech tts;
public MyAdapter(Context context, ArrayList<CreateList> galleryList) {
this.galleryList = galleryList;
this.context = context;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
.....
}
@Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
.....
.....
viewHolder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
.....
.....
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
// edit from original answer: I put double equal on this line
if(status == TextToSpeech.SUCCESS){
tts.setLanguage(Locale.UK);
playNextChunk(StringToSpeak);
}
}
});
}
private void playNextChunk(String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ttsGreater21(text);
} else {
ttsUnder20(text);
}}
@SuppressWarnings("deprecation")
private void ttsUnder20(String text) {
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, map);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void ttsGreater21(String text) {
String utteranceId = this.hashCode() + "";
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, params, utteranceId);
}
@Override
public int getItemCount() {
return galleryList.size();
}
.....
.....
}
我使用 Tabbed-Fragments 中的 RecyclerView 为我的应用程序开发了一个模块。
场景
使用 RecyclerView 在每个片段中显示了多个动态加载的图像。当用户点击任何图像时,系统会使用 TextToSpeech 说出有关它的一些信息。
当前代码
我正在为 RecyclerView 使用适配器 class,它成功地将图像加载到视图。这是代码:
import android.speech.tts.TextToSpeech;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private ArrayList<CreateList> galleryList;
private Context context;
TextToSpeech tts;
public MyAdapter(Context context, ArrayList<CreateList> galleryList) {
this.galleryList = galleryList;
this.context = context;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
.....
}
@Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
.....
.....
viewHolder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
.....
.....
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
if(status !=TextToSpeech.ERROR){
tts.setLanguage(Locale.UK);
}
}
});
tts.setPitch(pitch);
tts.setSpeechRate(speechRate);
tts.speak(StringToSpeak, TextToSpeech.QUEUE_FLUSH, null);
}
@Override
public int getItemCount() {
return galleryList.size();
}
.....
.....
}
如您所见,我在 viewHolder 上添加了一个 OnClickListener
,它使用 onInitListener
初始化 TTS 对象并朗读信息。但是每当我点击 Fragment 中的任何 image/view/item 时,它什么也说不出来。 LogCat 中没有崩溃,也没有异常,我得到的只是以下消息和其他消息:
I/TextToSpeech: Sucessfully bound to com.google.android.tts
W/TextToSpeech: speak failed: not bound to TTS engine
我尝试调试应用程序并发现在初始化 TTS 对象时 returns engine=Null
在这一行:
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
....});
在扩展 Activity 的其他 class 中,代码和 TTS 工作正常,但在我的 Adapter/Non-Activity class 中它不会启动 TTS,因为它无法绑定到 TTS 引擎。我尝试在我的适配器 class 中使用以下函数实现接口 implements TextToSpeech.OnInitListener
:
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.UK);
}
}
但没有结果 :( 我还尝试创建一个抽象 class 扩展 Activity,在其 OnCreate()
中实现 TTS 并包含一个自定义函数 SpeakMessage()
我尝试在我的适配器 Class 中调用但失败了。我已经花了几个小时试图找出问题及其解决方案,深入研究了 Whosebug 和其他网站上的每个 TTS 相关问题,但找不到任何我的问题的解决方案。请帮助我确定问题及其正确的解决方案。提前致谢。还有一件事,在视图的相同动作侦听器中,使用 MediaPlayer 播放录制的音频消息非常完美。唯一的问题是说出字符串消息使用 TTS。
我成功实现了文字转语音
下面是我的代码
我已经实施了两种方法,一种用于 <20 api,一种用于 >21api
@SuppressWarnings("deprecation")
private void ttsUnder20(String text) {
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, map);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void ttsGreater21(String text) {
String utteranceId = this.hashCode() + "";
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, params, utteranceId);
}
这里是调用这个方法的方法。
private void playNextChunk(String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ttsGreater21(text);
} else {
ttsUnder20(text);
}}
从 onInit 方法调用 playChunk 方法
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
playNextChunk(String text)
}
}
另一个建议文本到语音可以一次说出 4000 个字符,如果您有超过 4000 个字符的字符串,则需要分块播放。为此你需要实现这个监听器 tts.setOnUtteranceProgressListener
试试这个代码,我已经在你的适配器中添加了代码。
public class MyAdapter extends
RecyclerView.Adapter<MyAdapter.ViewHolder>{
private ArrayList<CreateList> galleryList;
private Context context;
TextToSpeech tts;
public MyAdapter(Context context, ArrayList<CreateList> galleryList) {
this.galleryList = galleryList;
this.context = context;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
.....
}
@Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
.....
.....
viewHolder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
.....
.....
tts=new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
// edit from original answer: I put double equal on this line
if(status == TextToSpeech.SUCCESS){
tts.setLanguage(Locale.UK);
playNextChunk(StringToSpeak);
}
}
});
}
private void playNextChunk(String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ttsGreater21(text);
} else {
ttsUnder20(text);
}}
@SuppressWarnings("deprecation")
private void ttsUnder20(String text) {
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, map);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void ttsGreater21(String text) {
String utteranceId = this.hashCode() + "";
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
tts.speak(text, TextToSpeech.QUEUE_FLUSH, params, utteranceId);
}
@Override
public int getItemCount() {
return galleryList.size();
}
.....
.....
}