我有TrackingService组件,可根据众包来跟踪我所在城市的公交车位置。 TrackingService在后台运行,然后将数据传输到服务器。我有一个Map Activity来显示总线的位置,在MainActivity中选择的用户(作为Filter)。
应用程序启动时,后台TrackingService在MainActivity中启动。
我在BroadcastReceiver的帮助下通知map
关于更新的lcoation的活动,如下面的代码所示。正在检索数据到地图活动,但我要解除注册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: com.bustracker.Map$1@2483d256
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: com.bustracker.Map$1@2483d256
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);
}
答案 0 :(得分:63)
如果您在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
是来自support library的一个类:
帮助您注册并向当前对象发送Intent广播。
这与允许系统范围广播的Context
上的相同方法不同。
另请参阅类似的问题/答案here。
答案 1 :(得分:2)
您必须在onResume()
中注册广播接收器,而在onPause()
中取消注册广播接收器,因为在片段或活动由于任何原因被销毁之前,必须确保调用它们。如果您在onStart()
中注册了广播接收器,而在onStop()
中未注册了广播接收器,则仍然可以正常工作,但是需要注意的是。如果您使用onStart()
和onStop()
,则不能保证广播接收器将在Android Lifecycle
onStop()
方法b.c中被注销。
例如:有两个活动(A和B)。从活动A移至活动B时,活动B的onStart()
和onResume()
可能在活动A的onStop()
之前被调用,而错误的活动(在这种情况下是活动A的方法{ {1}}可能会捕获活动B的广播接收器并将其注销,然后在活动B关闭或不可见时,调用其onStop()
方法以注销已经由{{1}取消注册的广播接收器}方法A,导致崩溃。
简而言之,即使活动A是不可见的,它的onStop()
方法仍然可以监听活动B的事件。因此,如果您只想在活动可见时监听事件,请使用{{1} }方法来注销广播接收器。
一般来说:
onStop()
上的注册保证onStop()
的取消注册
onPause()
上的注册会因活动生命周期而无法保证onResume()
的注册。
答案 2 :(得分:0)
请记住,您必须在相同的上下文中注册和取消注册。 例如,不要注册应用程序上下文并取消注册w /活动上下文。
不要这样做
getApplicationContext().registerReceiver(myReceiver, myIntentFilter);
unregisterReceiver(myReceiver);
改为(在活动中)
registerReceiver(myReceiver, myIntentFilter);
unregisterReceiver(myReceiver);
我通常在onPostResume()
或onResume()
内注册,并在<{em> onPause()
来电之后注册super.onPause()
。
示例:
protected void onPostResume() {
super.onPostResume();
registerReceiver(myReceiver, myIntentFilter);
}
protected void onPause() {
unregisterReceiver(tripInCartReceiver1);
//called after unregistering
super.onPause();
}