Java.lang.IllegalArgumentException: Получатель не зарегистрирован

У меня есть компонент TrackingService для отслеживания местоположения автобусов в моем городе на основе Crowdsourcing. Служба TrackingService работает в фоновом режиме, затем данные передаются на сервер. У меня есть активность карты для отображения местоположения шин, пользователя, выбранного в MainActivity (в качестве фильтра).

Служба фонового отслеживания запускается в MainActivity, когда приложение запускается.

Я не отмечаю активность map об обновленном lcoation с помощью BroadcastReceiver, как в приведенном ниже коде. Данные извлекаются на активность карты, но мне приходится сталкиваться с проблемой, чтобы отменить регистрацию моего bReceiver. Я хочу отменить регистрацию трансляции, когда приложение заходит в фоновом режиме или когда пользователь нажимает кнопку "Назад", но я получаю сообщение об ошибке ниже:

Как я могу это исправить?

Ошибка:

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

Класс 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);
           .....

     }  

}

Активность карты:

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

Ответ 1

Если вы зарегистрировались в onCreate(), вам нужно отменить регистрацию в onDestroy(). Если вы хотите отменить регистрацию в onStop(), вам необходимо зарегистрироваться в onStart().

Посмотрите на жизненный цикл деятельности здесь http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Причиной этого является то, что onStop() вызывается, когда Activity переходит в фоновый режим, но не обязательно уничтожается. Когда возвращается Activity на передний план onStart(), но не onCreate(), поэтому BroadcastReceiver не перерегистрируется. Затем, когда Activity возвращается в фоновый режим, onStop() пытается снова отменить регистрацию, но приемник не был зарегистрирован.

Вам также необходимо использовать LocalBroadcastManager, чтобы отменить регистрацию вашего ресивера, если вы его использовали для регистрации:

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

LocalBroadcastManager - это класс из библиотеки поддержки :

Помощник для регистрации и отправки трансляций намерений локальным объектам в вашем процессе.

Это отличается от тех же методов на Context, которые позволяют широковещательные системы всей системы.

Также см. аналогичный вопрос/ответ здесь.

Ответ 2

(Конечно, если хотите) Вы можете зарегистрировать или onStop() их регистрацию в onStop() и onResume() просто оберните их с помощью try-catch:

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

Или же

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

Ответ 3

Имейте в виду, что вы должны зарегистрироваться и отменить регистрацию в том же контексте. Например, не регистрируйте w/контекст приложения и не регистрируйте контекст активности.

Не делайте этого

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

Сделайте это вместо (внутри действия)

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

Я обычно регистрируюсь внутри onPostResume() или onResume() и отменил регистрацию в onPause() после вызова super.onPause().

Примеры:

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

    registerReceiver(myReceiver, myIntentFilter);
}

protected void onPause() {
    unregisterReceiver(tripInCartReceiver1);

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