TTS Error: leaked ServiceConnection android.speech.tts.TextToSpeech-ThrowExceptions

Exception or error:

Solution

It appears you must call the super method in onActivityResult

super.onActivityResult(requestCode, resultCode, data);

I am getting this error from TTS when I press the back button on my Activity. Aparently it is because I am not calling shutdown() but I am, see onDestroy() below. I have made an abstract TtsActivity Class which Activities Extend. I am calling super.onDestroy() in all subclasses.

12-05 18:04:05.268: ERROR/ActivityThread(30240): Activity com.mysite.myapp.ActivitySelectItGame has leaked ServiceConnection android.speech.tts.TextToSpeech$1@43e9b4a0 that was originally bound here
12-05 18:04:05.268: ERROR/ActivityThread(30240): android.app.ServiceConnectionLeaked: Activity com.mysite.myapp.ActivitySelectItGame has leaked ServiceConnection android.speech.tts.TextToSpeech$1@43e9b4a0 that was originally bound here
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:1121)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:1016)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ContextImpl.bindService(ContextImpl.java:863)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.content.ContextWrapper.bindService(ContextWrapper.java:347)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.speech.tts.TextToSpeech.initTts(TextToSpeech.java:467)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:433)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at com.mysite.android.library.activity.ActivityTTS.onActivityResult(ActivityTTS.java:98)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at com.mysite.myapp.ActivityGame.onActivityResult(ActivityGame.java:445)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.Activity.dispatchActivityResult(Activity.java:3890)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3557)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread.access$2800(ActivityThread.java:125)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2063)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.os.Handler.dispatchMessage(Handler.java:99)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.os.Looper.loop(Looper.java:123)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at android.app.ActivityThread.main(ActivityThread.java:4627)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at java.lang.reflect.Method.invokeNative(Native Method)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at java.lang.reflect.Method.invoke(Method.java:521)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-05 18:04:05.268: ERROR/ActivityThread(30240):     at dalvik.system.NativeStart.main(Native Method)

The Activity that my classes are extending

public abstract class ActivityTTS extends Activity implements OnInitListener {
    //TEXT TO SPEECH SERVICE
    public static final int CHECK_TTS_AVAILABILITY = 101;
    private static final String TAG = "ActivityTTS";
    private TextToSpeech mTts; //Text to speech library

    //MESSAGES
    private String NO_TTS_ANDROID_MARKET_REDIRECT = 
            "'SpeechSynthesis Data Installer' is not installed on your system, you are being redirected to" +
            " the installer package. You may also be able to install it my going to the 'Home Screen' then " +
            "(Menu -> Settings -> Voice Input & output -> Text-to-speech settings)";
    private String NO_TTS_AVAILABLE = 
            "'SpeechSynthesis Data Installer' is not available on your system, " +
            "you may have to install it manually yourself. You may also be able to install it my going to the 'Home Screen' " +
            "then (Menu -> Settings -> Voice Input & output -> Text-to-speech settings)";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate() called in ActivityTTS");

        try { //A weird error was occurring on some phones with the TTS, hence the try catch
            //TTS Service
            Intent checkIntent = new Intent();
            checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
            startActivityForResult(checkIntent, CHECK_TTS_AVAILABILITY);
        } catch (Exception e) {
            Toast.makeText(this, NO_TTS_AVAILABLE, Toast.LENGTH_LONG).show();
            finish();
        }

    }






    @Override
    protected void onStart() {
        super.onStart();


    }






    @Override
    protected void onStop() {
        super.onStop();
    }



    /**
     * Add a custom audio file for a particular 
     * audio element.
     * 
     * @param text
     * @param filename
     */
    protected void addSpeech(String text, String filename ) {
        mTts.addSpeech(text, filename);
    }



    /**
     * For TTS
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        try {
            //Log.d(TAG, "TTS Response: "+requestCode);
            if (requestCode == CHECK_TTS_AVAILABILITY) {
                if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {

                    // success, create the TTS instance
                    this.mTts = new TextToSpeech(this, this);

                } else {
                    // missing data, install it
                    Toast.makeText(this, NO_TTS_ANDROID_MARKET_REDIRECT, Toast.LENGTH_LONG).show();

                    PackageManager pm = getPackageManager();
                    Intent installIntent = new Intent();
                    installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                    ResolveInfo resolveInfo = pm.resolveActivity( installIntent, PackageManager.MATCH_DEFAULT_ONLY );

                    if( resolveInfo == null ) {
                       // Not able to find the activity which should be started for this intent
                        Toast.makeText(this, NO_TTS_AVAILABLE, Toast.LENGTH_LONG).show();
                    } else {
                       startActivity( installIntent );
                    }

                    finish();
                }
            }
        }catch (Exception e) {
            Log.e(TAG, "Unable to access service");
            finish();
        }

    }




    /**
     * Loads when the TTS is ready
     */
    @Override
    public void onInit(int status) {
        mTts.setLanguage(Locale.getDefault());
    }


    /**
     * Speak text
     */
    protected void speak(String text) {
        try{
            mTts.stop(); //Stop speaking
            mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
        }
        catch(Exception e) {
            Log.e(TAG, "TTS Failed - cannot say: "+text );
        }
    }


    /**
     * Speak a pre-recorded word
     */
    protected void speak(String text, File filename) {
        try{
            mTts.stop(); //Stop speaking
            mTts.addSpeech(text, filename.toString());
            mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
        }
        catch(Exception e) {
            Log.e(TAG, "TTS Failed - cannot say: "+text );
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();

        //Close the Text to Speech Library
        if(mTts != null) {

            mTts.stop();
            mTts.shutdown();
            Log.d(TAG, "TTS Destroyed");
        }
    }

    public void setLanguage(Locale audioLocale) {
        mTts.setLanguage(audioLocale);
    }
}

Here is the code related the the activity in ActivityGame

public abstract class ActivityGame extends ActivityTTS {

...

    protected void speak() {
        if (Logging.INFO) Log.i(TAG, "Speaking");

        if(this.mVoicePreference) {
            String word = mBoundService.getCurrentWord().getSpelling();


            if(WordRecordingHelper.recordingExists(word)) {

                try{
                    File f = new File(Constants.SDCARD_RECORDINGS+WordRecordingHelper.formatRecordedWord(word));
                    super.addSpeech(word, f.getAbsolutePath());
                } catch (Exception e) {
                    if(Logging.WARN) Log.w(TAG, "An error occurred while trying to use addSpeech()", e);
                }
            }


            //play the audio
            super.speak(word);  
        }
    }



    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        ...

        }



    @Override
    protected void onDestroy() {
        super.onDestroy();

        ....
        }


}

And here is ActivitySelectItGame, it doe not reference TTS at all, just extends ActivityGame

public class ActivitySelectItGame extends ActivityGame {
    ...
}

But I get the exact same problem from a totally unrelated Activity the extends ActivityTTS.

How to solve:
@Override
protected void onDestroy() {


    //Close the Text to Speech Library
    if(mTts != null) {

        mTts.stop();
        mTts.shutdown();
        Log.d(TAG, "TTS Destroyed");
    }
    super.onDestroy();
}

I think the problem is you are clsoing the mTts after the activity is destroyed. Try to use the code i have posted. Let me know if this works out

###

Each time you create an instance of mtts you need to shutdown it.

Or in other words, if you have more than one of new TextToSpeech(xxx) you need to have the same number of shutdown().

This works for me.

###

I’m not sure that onDestroy() is always called by the system. I’ve seen instances of it being skipped in my emulator. I can’t reproduce the circumstances every time though.
I’ve used TTS and have no problems with leaks. I call the mTts.shutdown() in onPause() and reinitialise it in onResume(). This works fine for me.

###

onCreate(), where you start the activity for result in order to check whether TTS is available, can be called by the framework many times. So I think you may be creating multiple TTS instances in onActivityResult(). For more information, see the diagram for the Activity class. Note that onCreate() can be called again after a call to onStop()

###

I got this Leaked Connection when using a WebView in my Fragment. In the onCreateView method I did setJavaScriptEnabled(true), which caused this error, when pressing back on the Activity. To get rid of it, I moved the set to onResume(), and also set it to false in onPause(), then problem disappeared.

Leave a Reply

Your email address will not be published. Required fields are marked *