【问题标题】:Android BroadcastReceiver: perform network call and play soundAndroid BroadcastReceiver:进行网络调用并播放声音
【发布时间】:2017-09-21 10:15:04
【问题描述】:

我正在编写一个警报应用程序。我有一个BroadcastReceiver,我用它和AlarmService 来处理警报响起。

BroadcastReceiver中,我想进行网络调用,然后如果满足某些条件,使用SoundPool播放声音。

但是,在运行BroadcastReceiver 的线程中不允许网络调用,所以我得到了NetworkOnMainThreadException。我尝试使用在后台线程上执行的IntentService,这让我解决了网络调用问题。但是,我还没有设法从中播放声音,并得到:

W/MessageQueue: Handler (android.media.SoundPool$EventHandler) {d64695a} sending message to a Handler on a dead thread

java.lang.IllegalStateException: Handler (android.media.SoundPool$EventHandler) {d64695a} sending message to a Handler on a dead thread

我的理解是SoundPool播放声音是异步播放的,线程已经死了。

怎么可能,从BroadcastReceiver开始同时执行网络调用和调用SoundPool

更新

这是代码的第一个版本,我试图在 BroadcastReceiver 中进行 HTTP 调用。在那之后是我收到的例外。请注意,虽然这里从未到达播放声音的部分,但如果我跳过 HTTP 调用,它确实可以工作。

package com.marksoft.alarm.alarm.events;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.media.SoundPool;

import com.marksoft.alarm.R;
import com.marksoft.alarm.alarm.data.IAlarmRepository;
import com.marksoft.alarm.alarm.data.InMemoryAlarmRepository;
import com.marksoft.alarm.backend.myApi.model.Prediction;
import com.marksoft.alarm.tfl.TflService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class BusStopCheckReceiver extends BroadcastReceiver {

    private static final Logger LOG = LoggerFactory.getLogger(com.marksoft.alarm.alarm.events.BusStopCheckReceiver.class);
    private SoundPool soundPool;
    private TflService tflService = new TflService();
    private IAlarmRepository alarmRepository = InMemoryAlarmRepository.getInstance();

    @Override
    public void onReceive(Context context, Intent intent) {

        // ...
        if(shouldSoundAlarm()) {
            playSound(context);
        }
        // ...
    }

    private boolean shouldSoundAlarm() {
        // HTTP call
        List<Prediction> predictions = tflService.getBusStopArrivals(alarm.getStopId());

        for(Prediction prediction : predictions) {
            LOG.info("Checking prediction {}", prediction);
            if(...) {
                LOG.info("Should sound alarm for prediction {}", prediction);
                return true;
            }
        }
        return false;
    }

    private int playSound(final Context context) {
        // Load the sound
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();
        soundPool = new SoundPool.Builder()
                .setAudioAttributes(attributes).build();
        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                soundPool.play(sampleId, 1, 1, 1, 0, 1f);
                LOG.info("Played sound");
            }
        });
        return soundPool.load(context, R.raw.bell1, 1);
    }
}

还有例外:

09-21 13:53:05.020 3218-3218/com.marksoft.alarm D/AndroidRuntime: Shutting down VM


        --------- beginning of crash
        09-21 13:53:05.021 3218-3218/com.marksoft.alarm E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.marksoft.alarm, PID: 3218
        java.lang.RuntimeException: Unable to start receiver com.marksoft.alarm.alarm.events.BusStopCheckReceiver: android.os.NetworkOnMainThreadException
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:3018)
        at android.app.ActivityThread.-wrap18(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1544)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
        Caused by: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
        at com.android.org.conscrypt.Platform.blockGuardOnNetwork(Platform.java:300)
        at com.android.org.conscrypt.OpenSSLSocketImpl.shutdownAndFreeSslNative(OpenSSLSocketImpl.java:1194)
        at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1189)
        at com.android.okhttp.Connection.closeIfOwnedBy(Connection.java:148)
        at com.android.okhttp.OkHttpClient$1.closeIfOwnedBy(OkHttpClient.java:77)
        at com.android.okhttp.internal.http.HttpConnection.closeIfOwnedBy(HttpConnection.java:137)
        at com.android.okhttp.internal.http.HttpTransport.disconnect(HttpTransport.java:135)
        at com.android.okhttp.internal.http.HttpEngine.disconnect(HttpEngine.java:573)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.disconnect(HttpURLConnectionImpl.java:134)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.disconnect(DelegatingHttpsURLConnection.java:93)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.disconnect(HttpsURLConnectionImpl.java)
        at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:99)
        at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
        at com.marksoft.alarm.tfl.TflService.getBusStopArrivals(TflService.java:78)
        at com.marksoft.alarm.alarm.events.BusStopCheckReceiver.shouldSoundAlarm(BusStopCheckReceiver.java:70)
        at com.marksoft.alarm.alarm.events.BusStopCheckReceiver.onReceive(BusStopCheckReceiver.java:55)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:3011)
        at android.app.ActivityThread.-wrap18(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1544) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6077) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 

【问题讨论】:

  • 你能不能把代码显示出来,这样我们就不用猜了
  • 我从代码的第一个版本中添加了 sn-p,我正在尝试进行 HTTP 调用并播放来自 BroadcastReceiver 的声音
  • 什么是 tflService.getBusStopArrivals?
  • tflService. getBusStopArrivals() 调用 Google Cloud Endpoint,这是导致异常的网络调用。我不认为代码是相关的。
  • 没错。我会为此创建一个作业服务,在单独的线程中异步执行网络请求,并为其设置回调以知道您何时必须播放声音

标签: android multithreading broadcastreceiver intentservice


【解决方案1】:

是的,您可以启动一个 IntentService 并在完成此 Intent 服务后,您可以再次通过 sendBroadCast 启动广播接收器并添加一些额外的内容,其 onReceive 方法会获得额外的匹配,然后播放声音。 所以这样你就可以同步网络通话和播放声音了。

【讨论】:

  • 这个答案对你有帮助吗..??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-18
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2018-07-13
  • 1970-01-01
相关资源
最近更新 更多