Android SBeacon Framework Beacon Scanning - scopetech/Mobile-Public GitHub Wiki
Beacon Scanning
SBeacon SDK v1.6.13
This guide covers scanning for SBeacon devices, retrieving scan results, and best practices for battery efficiency.
Start/Stop Scanning
Bind scanning to your UI lifecycle to conserve battery:
class BeaconsFragment : Fragment() {
override fun onResume() {
super.onResume()
startBeaconsScan()
}
override fun onPause() {
super.onPause()
stopBeaconsScan()
}
private fun startBeaconsScan() {
BLEManager.retrieveInstance(requireContext()).startBeaconsScan()
// Start updating UI with scan results
startPeriodicUIUpdate()
}
private fun stopBeaconsScan() {
BLEManager.retrieveInstance(requireContext()).stopBeaconsScan()
// Stop UI updates
stopPeriodicUIUpdate()
}
}
Scanning Methods
| Method | Description |
|---|---|
startBeaconsScan() |
Start continuous scanning for SBeacon devices |
stopBeaconsScan() |
Stop the current scan |
startQuickScan() |
Perform a brief scan (useful for quick discovery) |
Retrieve Beacon List
Poll for discovered beacons periodically:
private var updateJob: Job? = null
private fun startPeriodicUIUpdate() {
updateJob = lifecycleScope.launch {
while (isActive) {
updateBeaconList()
delay(1000) // Update every second
}
}
}
private fun stopPeriodicUIUpdate() {
updateJob?.cancel()
updateJob = null
}
private fun updateBeaconList() {
lifecycleScope.launch(Dispatchers.IO) {
val now = System.currentTimeMillis()
val beacons = BLEManager.retrieveInstance(requireContext()).allBeacons()
.filter { beacon ->
// Show paired beacons always
beacon.paired ||
// Show unpaired beacons seen within last 2 minutes
now - beacon.lastTimeUpdated < 120_000
}
.sortedBy { !it.paired } // Paired beacons first
withContext(Dispatchers.Main) {
// Update your RecyclerView or UI
adapter.submitList(beacons)
}
}
}
Filtering Strategy
| Beacon State | Visibility |
|---|---|
| Paired | Always shown regardless of last seen time |
| Unpaired | Shown if discovered within last 2 minutes |
The 2-minute window prevents stale unpaired beacons from cluttering the list while keeping recently discovered devices visible.
Beacon Properties
When displaying beacons, useful properties include:
val beacon: ScopeBeacon = ...
// Identification
beacon.macAddress // Unique identifier
beacon.name // Display name
beacon.minorId // Beacon minor ID
beacon.majorId // Beacon major ID
// State
beacon.paired // Whether beacon is paired
beacon.isCalibrated // Whether accelerometer is calibrated
beacon.tripStatus // Current trip status
// Timing
beacon.lastTimeUpdated // Last communication time
beacon.lastTimeScanned // Last scan detection time
// Battery
beacon.batteryVoltage // Current battery voltage
beacon.lastBatteryUpdate // When battery was last read
Check if Beacon is in Range
// Built-in helper method
val isInRange = beacon.isInRange()
// Uses 60-second threshold internally
// System.currentTimeMillis() - lastTimeUpdated < 60_000
Best Practices
Battery Efficiency
- Start scanning in
onResume(), stop inonPause() - Don't scan continuously when the UI isn't visible
- Use polling intervals of 1-2 seconds for UI updates
Threading
// Always access beacon list from IO dispatcher
lifecycleScope.launch(Dispatchers.IO) {
val beacons = BLEManager.retrieveInstance(context).allBeacons()
// Switch to Main for UI updates
withContext(Dispatchers.Main) {
updateUI(beacons)
}
}
Filter Stale Data
// Example: Only show beacons seen in last 2 minutes
val recentThreshold = System.currentTimeMillis() - (2 * 60 * 1000)
val recentBeacons = allBeacons.filter {
it.paired || it.lastTimeUpdated > recentThreshold
}
Next Steps
- Beacon Pairing - Pair with discovered beacons
- Event Handling - Subscribe to connection events