I am working on a bluetooth app using the AltBeacon library. It seems that only on instance of the BeaconManager
is allowed per application. The problem I am facing is this: I want a continuously running background service that constantly does bluetooth ranging and sends notifications. If I open my app (bring it to foreground) I was the service to pause ranging. The foreground activity will then do ranging and show content on the screen.
The problem is that the beacons manager (from BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);
) in the activity and service is the same instance. So when the activity gets closed, beaconManager.unbind(this);
gets called and the range notifier in the service no longer fires.
Is it possible to get two separate instances of beacon manager? If not, how can I do ranging in a continuous running service and an activity?
RangingActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
...
regionEstimote = new Region("estimote", null, null, null);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
notificationManager.cancel(NOTIFICATION_ID);
//beaconManager.unbind(this);
}
@Override
public void onBeaconServiceConnect() {
beaconManager.setRangeNotifier(new RangeNotifier() {
....
});
try {
beaconManager.startRangingBeaconsInRegion(regionEstimote);
} catch (RemoteException e) {
Log.e(TAG, "RangingActivity", e);
}
}
BeaconService.java
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(beaconHistory == null)
beaconHistory = new HashMap<Integer, Date>();
mBeaconManager = BeaconManager.getInstanceForApplication(this);
mBeaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
beaconHistory = null;
mBeaconManager.unbind(this);
}
@Override
public void onBeaconServiceConnect() {
mBeaconManager.setRangeNotifier(new RangeNotifier() {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if(ActivityBase.isActivityVisible()) { //don't do ranging logic if any activity from my app is in the foreground
return;
}
...
}
});
try {
mBeaconManager.startRangingBeaconsInRegion(regionMint);
} catch (RemoteException e) {
Log.e(TAG, "BeaconService", e);
}
}
This is a case where a custom android.app.Application
class is very useful. The BeaconManager
is a singleton so only one is allowed to exist at the same time. Similarly, the Application
class has a single instance per active Android application. If you want to do beacon detection in an Activity
and a Service
simultaneously, use the centralized Application
class to do the binding to BeaconManager
and then forward the callbacks to both your Activity
and your Service
.
You can see an example of binding to the BeaconManager
in an Application
class and then passing callbacks to an Activity
in the reference application here: https://github.com/AltBeacon/android-beacon-library-reference/blob/master/app/src/main/java/org/altbeacon/beaconreference/BeaconReferenceApplication.java