5

TextToSpeech 构造函数看起来像是被设计为由活动“拥有”的。我正在制作一个包含多个不同活动的应用程序,我不想为每个活动初始化一个新的 TextToSpeech 实例——我希望即使活动发生变化,语音也能顺利进行。

我的想法是让所有活动都访问一个静态 TextToSpeech 对象,由第一个活动初始化。

  1. 有谁知道 TextToSpeech 实现是否是线程安全的?我猜不是,但可能有人知道。
  2. 如果我使用默认 Activity 的上下文对其进行初始化,那么 TextToSpeech 实例会在 Activity 被销毁时停止工作吗?
4

5 回答 5

4

我从未尝试过,但我认为您可以将应用程序上下文作为构造函数中的参数传递,而不一定是 Activity。

但是注意文档,我看到TTS引擎有自己的排队系统,所以你可以多次调用speak而不用担心线程计时。

关于你的问题,我不确定第二个,但正如我首先写的那样,我会尝试传递一个应用程序上下文,而不是活动上下文。

关于第一,嗯,我猜每个引擎一次只有一个实例。而且您通常只有一个引擎,但同样,如果引擎控制查询排队,请不要担心线程。

于 2012-07-06T14:59:36.617 回答
3

感谢那些告诉我传递 ApplicationContext 的人。原来这很容易……难的是 TextToSpeech 对象是否保证线程安全。

感谢您的回答告诉我如何使某些东西成为线程安全的/假设它是,但问题是关于对象是否已经是。我可能应该说,我可以实现线程安全,但我想知道我是否需要打扰。而且我不想在不确定的情况下假设线程安全。

我跑了以下,它似乎工作。因此,我假设 Android SDK TTS 是线程安全的,但找不到任何文档说明在所有设备上假设它是安全的,所以我将暂时包装我的 TTS 实例!

package com.example.testproject;

import java.util.Random;

import android.os.Bundle;
import android.app.Activity;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;

public class TestActivity extends Activity implements OnInitListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tts = new TextToSpeech(getApplicationContext(), this);
    }

    TextToSpeech tts = null;

    @Override
    public void onInit(int arg0) {
        for (int i = 0; i < 100; ++i) {
            class Irritate implements Runnable {
                Irritate(int iIn) {
                    i = iIn;
                }

                @Override
                public void run() {
                    Random r = new Random();
                    try {
                        Thread.sleep(r.nextInt(2000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    tts.speak(Integer.toString(i), TextToSpeech.QUEUE_ADD, null);
                }

                int i;
            }

            Thread t = new Thread(new Irritate(i));

            t.start();
        }
    }
}
于 2012-07-09T21:21:06.157 回答
1

我一直使用 TTS 作为我开始ForResult 的 Activity。我只是向它发射一个意图,然后等待它回来。如果我没记错的话,如果返回一个按置信度排序的答案数组。所以你如果你没有上下文,那么我不相信有另一种方式来调用它(至少使用这个模型)。不确定是否有可以获取的对象引用。

但是,如果有,请使用您的想法。然后您可以扩展 Application 并在其中保存对您的 TTS 的静态引用。这样,您的所有活动都可以看到它。我认为这是您正在寻找的答案。

于 2012-07-06T14:31:05.897 回答
0

以上内容有助于我解决此问题。就我而言,我也有一个片段,所以我做了以下事情:

从一个片段(从一个片段,你想说“getActivity().getApplicationContext()”而不仅仅是“getApplicationContext()”):

public void onActivityResult(int requestCode, int resultCode, Intent data){
    if(requestCode == MY_DATA_CHECK_CODE){
        if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
            tts = new TextToSpeech(getActivity().getApplicationContext(), new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(int status) {
                    if(status == TextToSpeech.SUCCESS){
                        result = tts.setLanguage(Locale.UK);
                    }
                }
            });
        } else {
            // missing data, install it
            Intent installIntent = new Intent();
            // The ACTION_INSTALL_TTS_DATA intent will take the user to Android Market, and will let the user initiate the download
            installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
            startActivity(installIntent);
        }
    }
}
于 2015-03-22T19:56:55.773 回答
0

对于 GUI,TextToSpeech 不是线程安全的,因为从非 GUI 线程调用 TextToSpeech 侦听器方法。

如果您的侦听器方法与 GUI 交互,则必须包含代码以将 GUI 更改放入 GUI 线程的 Looper。

有很多关于如何将 GUI 命令包装在 Handler 中并将其发布到 GUI 线程的 looper 的示例。这是你要做什么的草图:

public class SpeechUtteranceListener extends UtteranceProgressListener {

    @Override
    public void onDone(String utteranceId) {
        Runnable guiCommand = new Runnable() {
            @Override
            public void run() {
                someButton.setEnabled(true);
                }
            }
        };
        runOnUiThread(asrStartCommand);
    }

    private void runOnUiThread(Runnable command){
        Looper.getMainLooper().post(command);
    }
}
于 2015-07-16T11:04:38.837 回答