我可以在Android中使用静态TextToSpeech吗?

时间:2012-07-06 14:25:41

标签: android text-to-speech

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

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

  1. 有没有人知道TextToSpeech实现是否是线程安全的?我猜不是,但有人可能知道。
  2. 如果我使用默认活动的上下文初始化它,那么当活动被销毁时,TextToSpeech实例是否会停止工作?

5 个答案:

答案 0 :(得分:4)

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

但是注意documentation,我发现TTS引擎有自己的排队系统,所以你可以多次打电话讲话而不用担心线程时间。

关于你的问题,我不确定第二个问题,但正如我先写的那样,我会尝试传递一个Application上下文,而不是Activity上下文。

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

答案 1 :(得分: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();
        }
    }
}

答案 2 :(得分:1)

我一直使用TTS作为我开始练习的活动。 我只是向它发出一个意图,然后等待它回来。 如果我没记错的话,如果返回一系列满意的答案。 所以如果你没有上下文,那么我不相信有另一种方法可以调用它(至少使用这个模型)。不确定是否有可以获得的对象引用。

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

答案 3 :(得分:0)

以上内容有助于我解决此问题。在我的情况下,我也有一个片段,所以,我做了以下:

从片段(来自片段,你想说&#34; getActivity()。getApplicationContext()&#34;而不仅仅是&#34; getApplicationContext()&#34;):

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);
        }
    }
}

答案 4 :(得分:0)

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

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

有很多关于如何在Handler中包装GUI命令并将其发布在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);
    }
}