#android #bluetooth-lowenergy #altbeacon
#Android #bluetooth-lowenergy #altbeacon
Вопрос:
перед всем я несколько раз прочитал все обсуждения о didRangeBeaconsInRegion в GitHub и stack-overflow. Я использовал BeaconManager.removeAllRangeNotifiers() в моем коде, ничего не изменилось. Я использую библиотеку altbeacon для сканирования UUID. сначала я просто использовал StartRanginginRegion и StopRanginginRegion, когда хотел прекратить сканирование. это вызвало проблему. казалось, что UUID были кэшированы на один раз, когда я отключил питание ibeacon. все еще найдено. после этого я использовал StartMonitorInRegion, а также starttranginginregion и никогда не останавливал MonitorInRegion. мое приложение должно сканировать один раз автоматически и останавливаться, затем пользователь может запустить его вручную, нажав кнопку, а затем снова остановить по истечении времени переднего плана сканирования. в моем окончательном коде появилась новая проблема. Функция didRangeBeaconsInRegion вызывается два раза при каждом запуске / остановке сканирования. Когда я запускаю фрагмент и запускаю сканирование. например, в каждом переднем плане я получаю beacon.size>0 и beacon.size<0 одновременно. Он ведет себя как два BeaconManager.bind , но я видел весь код. этого никогда не происходит.
HomeFragment.kt
class HomeFragment : Fragment(),RecyclerAdapterOutsideListener, BeaconConsumer {
lateinit var beaconManager: BeaconManager
val region = Region("myBeaons", null, null, null)
var endOfScaning=false
var isScanFirstTime=true
override fun getApplicationContext(): Context {
return activity!!.applicationContext
}
override fun unbindService(p0: ServiceConnection?) {
applicationContext.unbindService(p0!!)
}
override fun bindService(p0: Intent?, p1: ServiceConnection?, p2: Int): Boolean {
return applicationContext.bindService(p0, p1!!, p2)
}
override fun onBeaconServiceConnect() {
beaconManager!!.removeAllMonitorNotifiers();
beaconManager!!.addMonitorNotifier(object : MonitorNotifier {
override fun didDetermineStateForRegion(p0: Int, p1: Region?) {
Log.i(RangingActivity.TAG, "I have just switched from seeing/not seeing beacons: " p0);
}
override fun didEnterRegion(p0: Region?) {
Log.d(RangingActivity.TAG, "I just saw an beacon for the first time! $p0.id1");
}
override fun didExitRegion(p0: Region?) {
Log.d(RangingActivity.TAG, "I no longer see an beacon");
}
})
beaconManager.removeAllRangeNotifiers()
beaconManager.addRangeNotifier(object : RangeNotifier {
override fun didRangeBeaconsInRegion(p0: MutableCollection<Beacon>?, p1: Region?) {
if (p0!!.size > 0) {
Log.d("BeaconList", "didRangeBeaconsInRegion called with beacon count: " p0.size)
for (beacon in p0) {
Log.d("BeaconList", "uuid: " beacon.id1)
if (!finallist.uuids.contains(beacon.id1.toString())) {
finallist.uuids.add(beacon.id1.toString())
}
}
Log.d("deb","${p0.size} is > 0")
progress.visibility = View.GONE
homeRelative2.visibility = View.VISIBLE
}
if (p0.size<=0)
{
Log.d("deb","${p0.size} is <= 0")
Toast.makeText(applicationContext, "Searching is done. There are not any supported places here.", Toast.LENGTH_LONG).show()
progress.visibility = View.GONE
homeRelative2.visibility = View.VISIBLE
}
endOfScaning=true
if(endOfScaning)
{
Log.d("deb","inside stop function")
endOfScaning=false
stopScan()
}
}
})
}
override fun onCreate(savedInstanceState: Bundle?) {
beaconManager = BeaconManager.getInstanceForApplication(applicationContext)
beaconManager.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))
beaconManager.foregroundScanPeriod = 10000L
beaconManager.foregroundBetweenScanPeriod=2000L
beaconManager.updateScanPeriods()
beaconManager.bind(this)
startScan()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
imgScan.setOnClickListener {
finallist= uuidModel(ArrayList())
Log.d("clearing finallist","${finallist.uuids}")
recyclerAdapter.clearList()
recyclerAdapter.notifyDataSetChanged()
startScan()
progress.visibility=View.VISIBLE
homeRelative2.visibility=View.GONE
}
}
override fun onDestroy() {
super.onDestroy()
beaconManager.unbind(this)
}
override fun onStop() {
beaconManager.unbind(this)
super.onStop()
}
override fun onPause() {
super.onPause()
if (beaconManager.isBound(this)) {
beaconManager.unbind(this)
}
}
fun startScan() {
try {
if (isScanFirstTime and beaconManager.isBound(this))
{
beaconManager.startMonitoringBeaconsInRegion(region)
beaconManager.startRangingBeaconsInRegion(region)
isScanFirstTime = false
}
else
{
beaconManager.startRangingBeaconsInRegion(region)
}
} catch (e: RemoteException) {
Log.d("startScanFunction", "Start scan beacon problem", e)
}
}
fun stopScan() {
try {
if (beaconManager.isBound(this)) {
beaconManager.stopRangingBeaconsInRegion(region)
}
} catch (e: RemoteException) {
Log.d("startScanFunction", "Stop scan beacon problem", e)
}
}
}
Я мог бы решить эту проблему путем привязки перед каждым сканированием и отмены привязки после каждого сканирования в функциях startScan, StopScan.Но я боюсь, что это стандартный или правильный подход.
fun startScan() {
try {
if(!beaconManager.isBound(this))
{
beaconManager.bind(this)
}
if (isScanFirstTime and beaconManager.isBound(this))
{
beaconManager.startMonitoringBeaconsInRegion(region)
beaconManager.startRangingBeaconsInRegion(region)
isScanFirstTime = false
}
else
{
beaconManager.startRangingBeaconsInRegion(region)
}
}
catch (e: RemoteException) {
Log.d("startScanFunction", "Start scan beacon problem", e)
}
}
fun stopScan() {
try {
if (beaconManager.isBound(this))
{
beaconManager.stopRangingBeaconsInRegion(region)
beaconManager.unbind(this)
}
}
catch (e: RemoteException)
{
Log.d("startScanFunction", "Stop scan beacon problem", e)
}
}
Комментарии:
1. Проблема, вероятно, вызвана условиями гонки в асинхронных вызовах привязки / отмены привязки в сочетании со временем, когда вызываются startScanning / stopScanning. Это, вероятно, усугубляется сложностями жизненного цикла фрагмента. Хотя, вероятно, возможно заставить его работать с этой настройкой, потребуется тщательное протоколирование каждого из этих методов для отслеживания случаев, когда последовательность вызовов является неожиданной. Вероятно, будет быстрее выполнить рефакторинг кода, чтобы упростить эти события. Вызовите bind только один раз, если можете. Возможно, оставьте диапазон включенным, пока пользователь находится на экране.
2. Спасибо, Дэвид. Я не уверен, что могу задать другой вопрос или нет. Приведенный выше код я мог бы легко запустить на Android 9. но когда я запускаю его в Android 5.1 Lollipop. В нем говорилось, что вы должны использовать BeaconManager.bind(). Я использовал его в своем методе onCreate. странное поведение. После многих изменений я обнаружил, что мне нужно вызвать startRangingBeaconsInRegion() в функции onBeaconServiceConnect () для работы приложения. Я не знаю почему. в Android версии 9 я мог бы вызвать startRangingBeaconsInRegion в onCreate или button.setOnClickListener. Для чего это?
3. Я не уверен, где вы видите, что что-то подсказывает вам использовать «onBind» в Android 5.1. В общем, жизненный цикл фрагмента сложный и короткий. Я бы посоветовал вам вызвать bind() раньше — при запуске вашей активности или приложения, независимо от того, используется ли фрагмент еще. Затем не вызывайте unbind, пока ваша активность или приложение не будут уничтожены. Привязка в течение более длительного срока приведет к гораздо более предсказуемым результатам.