广播接收器组件不允许绑定服务。如何从广播接收器启动文本到语音?

3 android android-studio

我的应用程序给出了不允许 BroadcastReceiver 组件绑定到服务的错误。当短信到达时,我正在呼叫广播接收器,文本将转换为语音。我的接收器正确调用。

但我的代码给出了类似的错误

致命异常:主进程:texttospeech.tts.com.tts,PID:12811 java.lang.RuntimeException:无法启动接收器 texttospeech.tts.com.tts.ttsBroadcast:android.content.ReceiverCallNotAllowedException:不允许绑定 BroadcastReceiver 组件服务 在 android.app.ActivityThread.handleReceiver(ActivityThread.java:2618) 在 android.app.ActivityThread.access$1700(ActivityThread.java:148) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369) 在 android .os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5312) at java.lang.reflect。 Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901) at com.android。 internal.os.ZygoteInit.main(ZygoteInit.java:696) 引起:android.content.ReceiverCallNotAllowedException:BroadcastReceiver 组件不允许绑定到 android.speech.tts.TextToSpeech.connectToEngine(TextToSpeech.java:800) 处 android.speech.tts.TextToSpeech 处的 android.app.ReceiverRestrictedContext.bindService(ContextImpl.java:215) 处的服务。 initTts(TextToSpeech.java:770) at android.speech.tts.TextToSpeech.(TextToSpeech.java:723) at android.speech.tts.TextToSpeech.(TextToSpeech.java:702) at android.speech.tts.TextToSpeech.( TextToSpeech.java:686) at texttospeech.tts.com.tts.ttsBroadcast.onReceive(ttsBroadcast.java:23) at android.app.ActivityThread.handleReceiver(ActivityThread.java:2611) at android.app.ActivityThread.access$1700( ActivityThread.java:148) 在 android.app.ActivityThread$H。handleMessage(ActivityThread.java:1369) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java) :5312) 在 java.lang.reflect.Method.invoke(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit .java:901) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901) 处的reflect.Method.invoke(Method.java:372) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:第696章)com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901) 处的reflect.Method.invoke(Method.java:372) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:第696章)

这是我的代码

ttsBroadcast.java

public class ttsBroadcast extends BroadcastReceiver implements TextToSpeech.OnInitListener {
    private TextToSpeech tts;
    private String msg;
    @Override
    public void onReceive(Context context, Intent intent) {


        Toast.makeText(context,"sms recived",Toast.LENGTH_LONG).show();

        tts = new TextToSpeech(context,this);
        tts.speak(msg,TextToSpeech.QUEUE_FLUSH,null);


    }

    @Override
    public void onInit(int i) {

        tts.setLanguage(Locale.ENGLISH);
    }

}
Run Code Online (Sandbox Code Playgroud)

ple*_*mik 5

由于问题似乎仍然存在,我将添加一些行。首先我认为你应该有一个服务并从 BroadcastReceiver 调用这个服务。这可能是一种可能的实现方式。

广播接收器:

public class ReadMessageBroadcastReceiver extends BroadcastReceiver {

public final static String TAG = "ReadMessageBroadcastReceiver";

public ReadMessageBroadcastReceiver() {
}

@Override
public void onReceive(Context context, Intent intent) {
    if(intent.getAction().equals(Actions.ACTION_TTS_READ_MESSAGE)) {
        Log.v(TAG, "Read messages on tts received trough notification");
        String[] unreadMessages = intent.getStringArrayExtra(Constants.EXTRA_UNREAD_MESSAGES);
        if (unreadMessages != null) {
            Log.v(TAG, "Read messages on tts trough notification received " + unreadMessages.length
                    + " total messages");
            String messageNumber = context.getString(R.string.notification_message_number);

            ArrayList<String> allMessagesToRead = new ArrayList<>(unreadMessages.length);
            for (int i = 0; i < unreadMessages.length; i++) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(messageNumber);
                stringBuilder.append(" ");
                stringBuilder.append(i + 1);
                stringBuilder.append(" ");
                stringBuilder.append(unreadMessages[i]);
                stringBuilder.append(" ");
                allMessagesToRead.add(stringBuilder.toString());
            }

            Log.d(TAG, "Texts to read loud: " + allMessagesToRead);
            Intent speechIntent = new Intent(context, TextToSpeechService.class);
            speechIntent.putStringArrayListExtra(TextToSpeechService.TEXT_TO_READ, allMessagesToRead);
            context.startService(speechIntent);

        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

通过单击系统栏通知来调用此广播接收器。接收器需要在 AndroidManifest.xml 上声明一个特定的动作。

 <application>(all your stuff)
  <receiver
        android:name=".broadcastreceivers.ReadMessageBroadcastReceiver"
        android:enabled="true">
        <intent-filter>
            <action android:name="com.example.action.ACTION_TTS_READ_MESSAGE" />
        </intent-filter>
    </receiver>
 </application>
Run Code Online (Sandbox Code Playgroud)

您还需要在应用程序的某处声明此操作

public static final String ACTION_TTS_READ_MESSAGE = "com.example.action.ACTION_TTS_READ_MESSAGE";
Run Code Online (Sandbox Code Playgroud)

最后,您需要实现 TTSService 本身。我使用了这里的部分代码

public class TextToSpeechService extends Service implements TextToSpeech.OnInitListener {
public final static String TAG = "TextToSpeechService";

public static final String TEXT_TO_READ = "text";
private final String UTTERANCE_ID = "FINISHED_PLAYING";
private final int MULTI_LINE = 2;

private TextToSpeech tts;
private ArrayList<String> texts;
private boolean isInit;

private UtteranceProgressListener utteranceProgressListener = new UtteranceProgressListener() {
    @Override
    public void onStart(String utteranceId) {

    }

    @Override
    public void onDone(String utteranceId) {
        if (utteranceId.equals(UTTERANCE_ID)) {
            stopSelf();
        }
    }

    @Override
    public void onError(String utteranceId) {
        stopSelf();
    }
};

@Override
public void onCreate() {
    super.onCreate();
    tts = new TextToSpeech(getApplicationContext(), this);
    tts.setOnUtteranceProgressListener(utteranceProgressListener);
    Log.d(TAG, "onCreate");

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStartCommand");
    texts = intent.getStringArrayListExtra(TTSService.TEXT_TO_READ);

    if (isInit) {
        speak();
    }

    return TextToSpeechService.START_NOT_STICKY;
}

@Override
public void onDestroy() {
    if (tts != null) {
        tts.stop();
        tts.shutdown();
    }
    Log.d(TAG, "onDestroy");
    super.onDestroy();
}

@Override
public void onInit(int status) {
    Log.d(TAG, "onInit");
    if (status == TextToSpeech.SUCCESS) {
        int result = tts.setLanguage(Locale.getDefault());
        if (result != TextToSpeech.LANG_MISSING_DATA
                && result != TextToSpeech.LANG_NOT_SUPPORTED) {
            speak();
            isInit = true;
        }
    }
}

private void speak() {
    if (tts != null) {

        // Speak with 3 parameters deprecated but necessary on pre 21 version codes
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // This is a single message
            String utteranceId = null;
            if (texts.size() < MULTI_LINE) {
                // If is a single message this needs to be the last one
                utteranceId = UTTERANCE_ID;
            }
            tts.speak(texts.get(0), TextToSpeech.QUEUE_FLUSH, null, utteranceId);
            if (texts.size() >= MULTI_LINE) {
                for (int i = 1; i < texts.size(); i++) {
                    if (texts.size() - 1 == i) {
                        // If is the last message add the id
                        utteranceId = UTTERANCE_ID;
                    }
                    tts.speak(texts.get(i), TextToSpeech.QUEUE_ADD, null, utteranceId);
                }
            }
        } else {
            HashMap<String, String> myHashAlarm = null;
            if (texts.size() < MULTI_LINE) {
                myHashAlarm = new HashMap<>();
                myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UTTERANCE_ID);
            }
            tts.speak(texts.get(0), TextToSpeech.QUEUE_FLUSH, myHashAlarm);
            if (texts.size() >= MULTI_LINE) {
                for (int i = 1; i < texts.size(); i++) {
                    if (texts.size() - 1 == i) {
                        // If is the last message add the id
                        myHashAlarm = new HashMap<>();
                        myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
                                UTTERANCE_ID);
                    }
                    tts.speak(texts.get(i), TextToSpeech.QUEUE_ADD, myHashAlarm);
                }
            }
        }
    }
}

@Override
public IBinder onBind(Intent arg0) {
    return null;
}
Run Code Online (Sandbox Code Playgroud)

}

最后不要忘记在 AndroidManifest.xml 文件中注册您的服务

<service
    android:name=".services.TextToSpeechService"
    android:exported="false"/>
Run Code Online (Sandbox Code Playgroud)

不利的一面是,我会说启动时间太长了(一秒或两秒之间,具体取决于手机)。好的一面是,您不必让 tts 在启动和按需停止时一直运行。由于通过 Intent 传递给服务的参数是ArrayList<String>. 如果您只需要一个字符串,您可以简化实现。