2015-08-27 15 views
7

Ho un componente TrackingService per tracciare la posizione degli autobus nella mia città basata su Crowdsourcing. TrackingService funziona in background, quindi i dati vengono trasmessi al server. Ho un'attività mappa per visualizzare la posizione dei bus, l'utente selezionato in MainActivity (come filtro).java.lang.IllegalArgumentException: Ricevitore non registrato

Lo sfondo TrackingService viene avviato in MainActivity all'avvio dell'app.

Notifico l'attività map relativa alla lcoation aggiornata con l'ausilio di BroadcastReceiver come nel seguente codice. I dati vengono recuperati nell'attività della mappa, ma mi trovo di fronte a un problema per annullare la registrazione del mio bReceiver. Desidero annullare la registrazione della trasmissione quando l'app passa in background o quando l'utente preme il pulsante Indietro ma viene visualizzato l'errore seguente:

Come posso risolvere il problema?

Errore:

08-27 22:43:04.594: E/AndroidRuntime(19588): FATAL EXCEPTION: main 
08-27 22:43:04.594: E/AndroidRuntime(19588): Process: com.bustracker, PID: 19588 
08-27 22:43:04.594: E/AndroidRuntime(19588): java.lang.RuntimeException: Unable to stop activity {com.bustracker/com.bustracker.Map}: java.lang.IllegalArgumentException: Receiver not registered: [email protected] 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4156) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4219) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread.access$1500(ActivityThread.java:177) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1502) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.os.Handler.dispatchMessage(Handler.java:102) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.os.Looper.loop(Looper.java:145) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread.main(ActivityThread.java:5944) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at java.lang.reflect.Method.invoke(Native Method) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at java.lang.reflect.Method.invoke(Method.java:372) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1389) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1184) 
08-27 22:43:04.594: E/AndroidRuntime(19588): Caused by: java.lang.IllegalArgumentException: Receiver not registered: [email protected] 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:822) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:2038) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:528) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at com.bustracker.Map.onStop(Map.java:418) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1275) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.Activity.performStop(Activity.java:6493) 
08-27 22:43:04.594: E/AndroidRuntime(19588): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4151) 
08-27 22:43:04.594: E/AndroidRuntime(19588): ... 10 more 

classe TrackingService:

public class TrackingService extends Service implements 
     LocationListener { 
    public double pLong; 
    public double pLat; 
    ... 
     @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     detectLocation(); 
     return START_STICKY; 
    } 
    private void detectLocation() { 
     lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
     lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30 * 1000, 0, 
       this); 
    } 
    @Override 
    public void onLocationChanged(Location location) { 

     if (location != null) { 
     pLong = location.getLongitude(); 
     pLat = location.getLatitude(); 

     Intent intent = new Intent(Map.RECEIVE_latLng); 
     intent.putExtra("location",location); 
     LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
      ..... 

    } 

} 

Mappa attività:

public class Map extends FragmentActivity implements OnMapReadyCallback { 
    public static final String RECEIVE_latLng = "com.bustracker.RECEIVE_latLng"; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.map); 

     LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this); 
     IntentFilter intentFilter = new IntentFilter(); 
     intentFilter.addAction(RECEIVE_latLng); 
     bManager.registerReceiver(bReceiver, intentFilter); 

    } 


    private BroadcastReceiver bReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      if(intent.getAction().equals(RECEIVE_latLng)) { 
           Location location = intent.getParcelableExtra("location"); 
      double lng = location.getLongitude(); 
      double lat = location.getLatitude(); 
      LatLng ll = new LatLng(lat, lng); 
      MarkerOptions markerOpt = new MarkerOptions().title("My Location") 
         .position(ll); 
      System.out.println("ABC map: "+ lat + " ; " + lng); 
      myLocatMarker = map.addMarker(markerOpt); 
      } 
      } 
     };  
     } 
@Override 
protected void onStop() { 
    super.onStop(); 
    unregisterReceiver(bReceiver);  
} 

risposta

35

Se y o registrati in onCreate(), devi annullare la registrazione in onDestroy(). Se vuoi annullare la registrazione in onStop() devi registrarti in onStart().

Dai un'occhiata alla l'attività del ciclo di vita qui http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

La ragione di questo è che onStop() viene chiamato quando il Activity passa in secondo piano, ma non è necessariamente distrutta. Quando il Activity torna in primo piano, viene chiamato onStart(), ma nononCreate() in modo che lo BroadcastReceiver non venga registrato nuovamente. Quindi, quando lo Activity torna in background, onStop() tenta di annullare la registrazione, ma il ricevitore non è stato registrato.

È inoltre necessario utilizzare il LocalBroadcastManager per annullare la registrazione il ricevitore se è stato utilizzato per registrare in questo modo:

LocalBroadcastManager.getInstance(this).unregisterReceiver(bReceiver); 

LocalBroadcastManager è una classe dalla support library:

Helper to register for and send broadcasts of Intents to local objects within your process.

Questo è diverso dagli stessi metodi su Context che consentono le trasmissioni a livello di sistema.

Vedere anche una domanda/risposta simile here.

+0

Così ho registrato il 'bReceiver' nel onStart() ma sono ancora ottenere l'errore. –

+0

@Mr Asker Puoi mostrare il nuovo codice e il nuovo stacktrace? –

+0

Grazie, non l'ho nemmeno notato. Ho aggiornato la risposta ora. Credo ancora che anche i commenti che ho fatto sui metodi del ciclo di vita siano validi, quindi li lascio lì. –

3

(Naturalmente, se si vuole) Si può registrare o annullare la registrazione in onStop() e onResume() basta avvolgerlo con try-catch:

try{ getActivity().registerReceiver(receiver,filter); } catch (Exception e){ // already registered } O

try{ getActivity().unregisterReceiver(receiver); } catch (Exception e){ // already unregistered }

0

Tenete a mente che è necessario registrarsi e annullare la registrazione nello stesso contesto. Ad esempio, non registrare con il contesto dell'applicazione e annullare la registrazione w/il contesto dell'attività.

Non fare questo

getApplicationContext().registerReceiver(myReceiver, myIntentFilter); 
unregisterReceiver(myReceiver); 

fare questo, invece (all'interno di un'attività)

registerReceiver(myReceiver, myIntentFilter); 
unregisterReceiver(myReceiver); 

Io di solito registro all'interno onPostResume() o onResume() e annullare la registrazione in onPause()dopo il super.onPause() chiamata.

Esempi:

protected void onPostResume() { 
    super.onPostResume(); 

    registerReceiver(myReceiver, myIntentFilter); 
} 

protected void onPause() { 
    unregisterReceiver(tripInCartReceiver1); 

    //called after unregistering 
    super.onPause(); 
} 
Problemi correlati