TextToSpeech.setEngineByPackageName() triggers Nul

2019-07-15 04:41发布

My activity's onInit() contains a call to TextToSpeech.setEngineByPackageName():

  tts = new TextToSpeech(this, this);
  tts.setEngineByPackageName("com.ivona.tts.voicebeta.eng.usa.kendra");

It works on an Android 2.2.2 device, but on an Android 2.3.4 device it produced a NullPointerException, with the following stack trace:

 E/TextToSpeech.java - setEngineByPackageName(3423): NullPointerException
 W/System.err(3423): java.lang.NullPointerException
 W/System.err(3423):    at android.os.Parcel.readException(Parcel.java:1328)
 W/System.err(3423):    at android.os.Parcel.readException(Parcel.java:1276)
 W/System.err(3423):    at android.speech.tts.ITts$Stub$Proxy.setEngineByPackageName(ITts.java:654)
 W/System.err(3423):    at android.speech.tts.TextToSpeech.setEngineByPackageName(TextToSpeech.java:1356)

Since I am providing a hard-coded string parameter, I know that the parameter isn't what's causing the NullPointerException.

I also know that setEngineByPackageName() is deprecated but that's only since API 14, so this couldn't be the reason.

Any idea what could be causing this NullPointerException?

EDIT: I wouldn't have been concerned with the "why" if this didn't result in an endless bombardment of:

I/TextToSpeech.java(3652): initTts() successfully bound to service

Followed by calls to onInit() (by the system, not by my code).

My hope is that if I underderstand why this is happening, I can stop the bombardment of onInit()s and recover gracefully from the error.

2条回答
三岁会撩人
2楼-- · 2019-07-15 05:13

Attempting to investigate this myself, in case an expert on the subject isn't around:

The NullPointerException stack trace is printed by setEngineByPackageName() itself in the catch handler for this try clause:

try {
    result = mITts.setEngineByPackageName(enginePackageName);
    if (result == TextToSpeech.SUCCESS){
        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
    }
} 

Which suggests that either of the following is null:

  1. mITts
  2. mCachedParams

mCachedParams is unlikely to be the null one because it is initialized in the constructor. So this leaves us with mITts:

If I examine TextToSpeech.initTts() I can easily spot 2 points in which mITts can remain null:

  1. onServiceConnected()
  2. onServiceDisconnected()

But why this is happening only on the 2.3.4 device? This is still a mystery.

Possible clue: The method TextToSpeech.initTts() ends with the following comment:

mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
// TODO handle case where the binding works (should always work) but
//      the plugin fails

Which may explain why I receive a barrage of onInit()s ("initTts() successfully bound to service"): Binding always works, but since the package is not installed, "the plugin fails".

The question now is how to stop this endless loop...

查看更多
迷人小祖宗
3楼-- · 2019-07-15 05:15

Is the TTS engine you are referencing installed on the 2.3.4 device? If it is, it might be a platform bug.

EDIT: Don't remember what results I got when I did this, but calling setEngineByPackageName() when the package doesn't exists is not a good idea. Check if it is installed and don't try to use it if it's not. Something like:

boolean isPackageInstalled(String packageName) {
  PackageManager pm = context.getPackageManager();
  try {
    PackageInfo pi = pm.getPackageInfo(packageName, 0);

    return pi != null;
  } catch (NameNotFoundException e) {
    return false;
  }
}
查看更多
登录 后发表回答