2012-07-06 81 views
4

TextToSpeech構造函數看起來像它被設計爲由活動「擁有」。我正在製作一個包含多個不同活動的應用程序,而且我不想爲每個應用程序都初始化一個新的TextToSpeech實例 - 即使活動正在改變,我也希望演講能夠順利進行。我可以在Android中使用靜態TextToSpeech嗎?

我的想法是讓一個靜態的TextToSpeech對象訪問所有活動,由第一個活動初始化。

  1. 有誰知道TextToSpeech實現是否線程安全?我猜不是,但有人可能知道。
  2. 如果我用默認活動的上下文初始化它,TextToSpeech實例會在活動被銷燬時停止工作嗎?

回答

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

我一直使用TTS作爲一個Activity,我開始了結果。 我只是向它發射一個意圖,然後等待它回來。 如果我沒有記錯的話,如果返回按自信排序的答案數組。 所以,如果你沒有上下文,那麼我不認爲有另一種方式來調用它(至少使用這種模式)。不知道是否有可以獲取的對象引用。

但是,如果有,使用你的想法。然後,您可以擴展應用程序並在其中保存對您的TTS的靜態引用。這樣它就可以看到你的所有活動。我認爲這是你正在尋找的答案。

+1

你的意思是語音識別?如果我正確地理解了這個問題,他的意思是相反的,也就是說,通過文本產生真正的聲音 – mdelolmo 2012-07-06 14:45:55

+0

噢。你是對的。我所描述的是語音識別。然而,我在第二段中擴展Application的模式仍然是他正在尋找的解決方案。 – 2012-07-06 14:48:42

+2

是的,我同意,他應該通過應用程序上下文而不是活動上下文 – mdelolmo 2012-07-06 15:00:31

4

我從來沒有嘗試過,但我認爲你可以傳遞一個應用程序上下文作爲參數在構造函數中,不一定是一個活動。

但是關注documentation,我看到TTS引擎有自己的排隊系統,所以你可以多次打電話說話而不用擔心線程的時間安排。

考慮到你的問題,我不確定第二個問題,但是正如我先寫的那樣,我會嘗試傳遞一個Application上下文,而不是Activity上下文。

關於第一,好吧,我猜每個引擎一次有一個實例。而且通常只有一個引擎,但是如果引擎控制查詢排隊,則不要擔心線程。

+0

嗨@mdelolmo,謝謝你回答第二部分。我知道TTS有自己的排隊系統,但這並不能保證線程安全。例如,它不能保證兩個線程可以同時對語音進行排隊,而不會中斷對象。對此有何想法? – Hbcdev 2012-07-09 11:10:08

+0

@Hbcdev,我的直覺告訴我它是線程安全的。你可能不相信我的直覺,但我認爲引擎應該站在不同線程的獨立調用。例如,兩個不同的應用程序(前臺活動和本地輔助功能輔助技術)同時獲得服務,這是不尋常的,但可能會發生。但是,如果您想完全確定,您可以爲TTS服務保留一個靜態單例實例,儘管您可以對應用程序上下文有一個靜態引用。 – mdelolmo 2012-07-09 19:51:09

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

文字轉語音不是線程安全相對於該GUI,因爲文字轉語音監聽方法是從非GUI線程調用。

如果您的偵聽器方法與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); 
    } 
} 
相關問題