5

TextToSpeechコンストラクターは、Activityによって「所有」されるように設計されているように見えます。複数の異なるアクティビティを含むアプリを作成していますが、それぞれに新しいTextToSpeechインスタンスを初期化する必要はありません。アクティビティが変更されても、スピーチをスムーズに続行したいと考えています。

私の考えは、静的なTextToSpeechオブジェクトにすべてのアクティビティからアクセスさせ、最初のアクティビティによって初期化することです。

  1. TextToSpeechの実装がスレッドセーフかどうか誰かが知っていますか?私は推測していませんが、そこにいる誰かが知っているかもしれません。
  2. デフォルトのアクティビティのコンテキストで初期化した場合、アクティビティが破棄されるとTextToSpeechインスタンスは機能しなくなりますか?
4

5 に答える 5

4

私はそれを試したことがありませんが、必ずしもアクティビティではなく、コンストラクターのパラメーターとしてアプリケーションコンテキストを渡すことができると思います。

しかし、ドキュメントに注意を払うと、TTSエンジンには独自のキューイングシステムがあるため、スレッドのタイミングを気にせずに何度も音声合成を呼び出すことができます。

あなたの質問に関しては、2番目についてはよくわかりませんが、最初に書いたように、アクティビティコンテキストではなく、アプリケーションコンテキストを渡してみます。

ナンバーワンについては、まあ、一度にエンジンごとに1つのインスタンスがあると思います。また、通常はエンジンが1つだけですが、エンジンがクエリキューイングを制御する場合は、スレッドについて心配する必要はありません。

于 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をStartedForResultのアクティビティとして使用してきました。私はそれにインテントを発射し、それが戻ってくるのを待ちます。私が正しく覚えていれば、ifは信頼度でソートされた回答の配列を返します。したがって、コンテキストがない場合は、(少なくともこのモデルを使用して)それを呼び出す別の方法があるとは思いません。あなたがそれのために得ることができるオブジェクト参照があるかどうかわからない。

ただし、ある場合は、あなたのアイデアを使用してください。次に、アプリケーションを拡張して、TTSへの静的参照をそこに保持できます。そうすれば、すべてのアクティビティに表示されます。これがあなたが探している答えだと思います。

于 2012-07-06T14:31:05.897 に答える
0

上記は、この問題の解決に役立ちました。私の場合、フラグメントもあったので、次のようにしました。

フラグメントから(フラグメントから、単に「getApplicationContext()」ではなく「getActivity()。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

TextToSpeechリスナーメソッドは非GUIスレッドから呼び出されるため、TextToSpeechはGUIに関してスレッドセーフではありません。

リスナーメソッドがGUIと対話する場合は、GUIの変更をGUIスレッドのルーパーに配置するためのコードを含める必要があります。

GUIコマンドをハンドラーでラップしてGUIスレッドのルーパーに投稿する方法の例はたくさんあります。これがあなたがすることのスケッチです:

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 に答える