2017-09-21 9 views
1

Je suis en train d'écrire une application d'alarme. J'ai un BroadcastReceiver, que j'utilise avec le AlarmService pour gérer les alarmes qui se déclenchent.Android BroadcastReceiver: effectuer un appel réseau et jouer le son

Dans le BroadcastReceiver, je souhaite effectuer un appel réseau, puis, si certaines conditions sont remplies, émettre un son à l'aide du SoundPool.

Toutefois, les appels réseau ne sont pas autorisés dans le thread exécutant BroadcastReceiver, donc j'obtiens un NetworkOnMainThreadException. J'ai essayé d'utiliser un IntentService, qui est exécuté sur un thread d'arrière-plan, ce qui me permet de contourner le problème d'appel réseau. Cependant, je ne l'ai pas réussi à jouer un son de celui-ci, et d'obtenir:

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 

Je crois comprendre que le SoundPool jouant les sons joue de manière asynchrone, et le fil est mort.

Comment est-il possible, à partir d'un BroadcastReceiver, d'effectuer l'appel réseau et d'appeler le SoundPool?

MISE À JOUR

Ceci est la première version du code, où je suis en train de faire l'appel HTTP à l'intérieur du BroadcastReceiver. Après c'est l'exception que je reçois. Notez que, bien que la partie jouant le son ne soit jamais atteinte ici, cela fonctionne si j'ignore l'appel 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); 
    } 
} 

Et l'exception:

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)  
+0

pouvez-vous, comme, afficher le code, donc nous ne devrons pas deviner –

+0

J'ai ajouté l'extrait de la première version du code, où j'essaye de faire l'appel HTTP et de jouer le son du 'BroadcastReceiver ' –

+0

qu'est-ce que tflService.getBusStopArrivals? –

Répondre

1

Oui, vous pouvez démarrer une IntentService et à la fin de ce service intention, vous pouvez à nouveau démarrer le BroadcastReceiver par sendBroadCast et mettre un peu plus et sa méthode OnReceive obtenir ce supplément correspondre et ensuite jouer le son. Ainsi, vous pouvez synchroniser l'appel réseau et lire le son.

+0

cette réponse vous est-elle utile? –