当前位置: 首页 > 知识库问答 >
问题:

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

东门新立
2023-03-14

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

但我的代码给出的错误如下

致命html" target="_blank">异常:主进程:texttospeech。tts。通用域名格式。tts,PID:12811 java。lang.RuntimeException:无法启动接收器texttospeech。tts。通用域名格式。tts。ttsBroadcast:android。所容纳之物ReceiverCallNotAllowedException:不允许BroadcastReceiver组件绑定到android上的服务。应用程序。ActivityThread。android上的HandlerReceiver(ActivityThread.java:2618)。应用程序。ActivityThread。在android上访问1700美元(ActivityThread.java:148)。应用程序。android上的ActivityThread$H.handleMessage(ActivityThread.java:1369)。操作系统。处理程序。android上的dispatchMessage(Handler.java:102)。操作系统。活套。android上的loop(Looper.java:135)。应用程序。ActivityThread。java上的main(ActivityThread.java:5312)。lang.reflect。方法在java中调用(本机方法)。lang.reflect。方法在com上调用(方法java:372)。Android内部的操作系统。ZygoteInit$MethodandArgscaler。在com上运行(ZygoteInit.java:901)。Android内部的操作系统。合子岩。main(ZygoteInit.java:696)由:android引起。所容纳之物ReceiverCallNotAllowedException:不允许BroadcastReceiver组件绑定到android上的服务。应用程序。ReceiverRestrictedContext。android上的bindService(ContextImpl.java:215)。演讲tts。TextToSpeech。android上的connectToEngine(TextToSpeech.java:800)。演讲tts。TextToSpeech。android上的initTts(TextToSpeech.java:770)。演讲tts。TextToSpeech。(TextToSpeech.java:723)在android上。演讲tts。TextToSpeech。(TextToSpeech.java:702)在android上。演讲tts。TextToSpeech。(TextToSpeech.java:686)位于TextToSpeech。tts。通用域名格式。tts。ttsBroadcast。android上的onReceive(ttsBroadcast.java:23)。应用程序。ActivityThread。HandlerReceiver(ActivityThread.java:2611)

这是我的密码

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

}

共有1个答案

锺离嘉容
2023-03-14

由于这个问题似乎仍然存在,我将添加一些行。首先,我认为您应该有一个服务,并从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);

        }
    }
  }
}

通过单击系统栏通知调用此广播接收器。接收器需要通过特定操作在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>

您还需要在应用程序中的某个位置声明此操作

public static final String ACTION_TTS_READ_MESSAGE = "com.example.action.ACTION_TTS_READ_MESSAGE";

最后,您需要实现TTS服务本身。我在这里使用了部分代码

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

}

最后,不要忘记在AndroidManifest上注册您的服务。xml文件

<service
    android:name=".services.TextToSpeechService"
    android:exported="false"/>

不利的一面是,我会说启动需要太多时间(根据手机在1秒或2秒之间)。好的一面是,您不会让tts在启动和按需停止时一直运行。实现了一些逻辑来确定是否是系列中的最后一条消息,因为在Intent上传递给服务的参数是ArrayList

 类似资料:
  • 问题内容: 有人可以解释和之间的确切区别吗? 在什么情况下我们必须使用每个Receiver类? 问题答案: 和之间只有一个区别。 当您收到内部广播方法时, 假设, BroadcastReceiver : 它 不保证 该 CPU将保持清醒 ,如果你启动一些长时间运行的进程。CPU可能会立即回到睡眠状态。 WakefulBroadcastReceiver : 这是 保证 该 CPU将保持清醒 ,直到你

  • 我有一个监控wifi连接的小部件,所以我启动了一项服务来启动广播接收器来检测网络变化。除了我退出主应用程序外,一切都正常:服务停止。 因此,我在小部件中启动了一个报警管理器,它几乎每分钟都会唤醒一次,并检查主应用程序是否已退出。如果是这种情况,我尝试重新启动我的wifi监控服务,但这次它崩溃了,并显示以下消息: 不允许开启服务Intent{cmp=包。CallbackNetworkWidgetSe

  • 我目前正在使用SharedReferences跟踪通过AlarmManager启动的BroadcastReceiver中要执行工作的项列表。除了一个特定的场景外,一切都很好。当我触发一个新项目来执行工作时,让它完成工作,然后删除该项目(全部通过SharedReferences编辑),它在应用程序运行时工作得很好。当列表中没有任何内容,我打开任务管理器并终止应用程序时,该项突然出现在Broadcas

  • 4.2.1.3 内部广播接收器 内部广播接收器是广播接收器,它将永远不会收到从内部应用以外发送的任何广播。 它由几个内部应用组成,用于保护内部应用处理的信息或功能。 要点(接收广播): 定义内部签名权限来接收广播。 声明使用内部签名权限来接收结果。 将导出属性显式设置为true。 需要静态广播接收器定义的内部签名权限。 需要内部签名来注册动态广播接收器。 确认内部签名权限是由内部应用定义的。 尽管

  • 4.2.1.2 公共广播接收器 公共广播接收器是可以从未指定的大量应用程序接收广播的广播接收器,因此有必要注意,它可能从恶意软件接收广播。 要点(接收广播): 将导出属性显式设为true。 小心并安全地处理收到的意图。 返回结果时,不要包含敏感信息。 公共广播接收器的示例代码可以用于静态和动态广播接收器。 PublicReceiver.java package org.jssec.android.

  • 4.2.1.1 私有广播接收器 私人广播接收器是最安全的广播接收器,因为只能接收到从应用内发送的广播。 动态广播接收器不能注册为私有,所以私有广播接收器只包含静态广播接收器。 要点(接收广播): 将导出属性显示设为false 小心并安全地处理收到的意图,即使意图从相同的应用中发送 敏感信息可以作为返回结果发送,因为请求来自相同应用 AndroidManifest.xml <?xml version