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
You should extend the Applicaton class and start region background monitoring like it is explained here (see "Starting an App in the Background").
In order to do the ranging, in the same class implement RangeNotifier:
public class AndroidApp extends Application implements BootstrapNotifier, RangeNotifier {...
Start the ranging in didEnterRegion:
@Override
public void didEnterRegion(Region region) {
try {
mBeaconManager.startRangingBeaconsInRegion(region);
}
catch (RemoteException e) {
if (BuildConfig.DEBUG) Log.d(Const.TAG, "Can't start ranging");
}
}
Implement didRangeBeaconsInRegion method:
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Beacon firstBeacon = beacons.iterator().next();
if (BuildConfig.DEBUG) Log.d(Const.TAG, "Beacon ranged: UUID: "
+ firstBeacon.getId1().toString() + " Major: "
+ firstBeacon.getId2().toString() + " Minor: "
+ firstBeacon.getId3().toString());
// Do something with the result
// Stop ranging
try {
mBeaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With