非 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();
}
.....
.....
}