2016-12-25 6 views
0

Я использую Android Beacon Library для сканирования сигналов Eddystone Beacons для Android. Я запускаю мониторинг после того, как услуга радиомаяка подключена, а затем начните колебаться, когда найден маяк.Остановить сканирование маяков: stopRangingBeaconsInRegion() не работает

Мне нужно прекратить сканирование маяков (остановить мониторинг и настройку) по выбору пользователя. Я использую

beaconManager.stopMonitoringBeaconsInRegion(region); 
beaconManager.stopRangingBeaconsInRegion(region); 

, чтобы остановить сканирование внутри моей остановкиScan(). Но ранжирование не прекращается, хотя мониторинг останавливается. Есть ли что-то, что я делаю неправильно?

Вот полный код:

public class BlankFragment extends Fragment implements BeaconConsumer { 


    public BlankFragment() { 
     // Required empty public constructor 
    } 

    private static final int PERMISSION_REQUEST_FINE_LOCATION = 1; 
    private Region region; 
    private Map<String /* uid */, Beacon> deviceToBeaconMap = new HashMap<>(); 

    String LOG_TAG = BlankFragment.class.getSimpleName(); 
    SharedPreferences sp; 
    View rootView; 


    private BeaconManager beaconManager; 
    boolean isScanning = false; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); 
     sp.registerOnSharedPreferenceChangeListener(listener); 


     beaconManager = BeaconManager.getInstanceForApplication(getContext()); 

     beaconManager.getBeaconParsers().add(new BeaconParser(). 
       setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19")); 

     beaconManager.bind(this); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     rootView = inflater.inflate(R.layout.fragment_near_me, container, false); 
     return rootView; 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 

     if (isScanning) 
      stopScan(); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 

     deviceToBeaconMap.clear(); 
     beaconManager.unbind(this); 
    } 

    @Override 
    public void onBeaconServiceConnect() { 

     region = new Region("nearMeScanning", null, null, null); 
     Log.i(LOG_TAG, "OnBeaconServiceConnect called"); 

     beaconManager.addMonitorNotifier(new MonitorNotifier() { 
      @Override 
      public void didEnterRegion(Region region) { 
       try { 
        beaconManager.startRangingBeaconsInRegion(region); 
        Log.i(LOG_TAG, "In beacon region"); 
       } catch (RemoteException e) { 
        Log.e(LOG_TAG, "Remote Exception while starting Ranging", e); 
       } 
      } 

      @Override 
      public void didExitRegion(Region region) { 
       try { 
        beaconManager.stopRangingBeaconsInRegion(region); 
        Log.i(LOG_TAG, "Exited beacon region"); 
       } catch (RemoteException e) { 
        Log.e(LOG_TAG, "Remote Exception while stoping Ranging", e); 
       } 
      } 

      @Override 
      public void didDetermineStateForRegion(int i, Region region) { 
       Log.i(LOG_TAG, "State of region changed " + i); 

      } 
     }); 

     beaconManager.addRangeNotifier(new RangeNotifier() { 
      @Override 
      public void didRangeBeaconsInRegion(Collection<org.altbeacon.beacon.Beacon> beacons, Region region) { 
       if (beacons.size() > 0) { 
        for (org.altbeacon.beacon.Beacon scannedBeacon : beacons) { 

         setOnLostRunnable(); 

         String deviceUUID = scannedBeacon.getId1().toString().substring(2) + scannedBeacon.getId2().toString().substring(2); 
         String deviceAddress = scannedBeacon.getBluetoothAddress(); 
         int rssi = scannedBeacon.getRssi(); 

         Beacon beacon; 

         if (!deviceToBeaconMap.containsKey(deviceUUID)) { 

          beacon = new Beacon(deviceAddress, rssi, deviceUUID); 
          deviceToBeaconMap.put(deviceUUID, beacon); 

          if (BuildConfig.DEBUG) 
           Log.d(LOG_TAG, "New Beacon added " + deviceUUID + " DeviceAddress " + deviceAddress); 


         } else { 
          deviceToBeaconMap.get(deviceUUID).lastSeenTimestamp = System.currentTimeMillis(); 
          deviceToBeaconMap.get(deviceUUID).rssi = rssi; 
         } 

        } 
       } 
      } 
     }); 

     if (sp.getBoolean(Constants.SharedPreferences.IS_VISIBILITY_ON, false)) { 
      refreshScan(); 
     } else { 
      visbilityOffTasks(); 
     } 
    } 

    @Override 
    public Context getApplicationContext() { 
     return getActivity().getApplicationContext(); 
    } 

    @Override 
    public void unbindService(ServiceConnection serviceConnection) { 
     getActivity().unbindService(serviceConnection); 
    } 

    @Override 
    public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) { 
     return getActivity().bindService(intent, serviceConnection, i); 
    } 

    private void refreshScan() { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if (getActivity().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
       if (BuildConfig.DEBUG) 
        Log.d(LOG_TAG, "Will check for permissions"); 
       requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 
         PERMISSION_REQUEST_FINE_LOCATION); 
      } else { 
       if (sp.getBoolean(Constants.SharedPreferences.IS_VISIBILITY_ON, false)) 
        startScan(); 
      } 
     } else { 
      if (sp.getBoolean(Constants.SharedPreferences.IS_VISIBILITY_ON, false)) 
       startScan(); 
     } 
    } 

    private void startScan() { 
     if (sp.getBoolean(Constants.SharedPreferences.IS_VISIBILITY_ON, false)) { 
      Log.i(LOG_TAG, "Starting scanning"); 
      try { 
       beaconManager.startMonitoringBeaconsInRegion(region); 
       isScanning = true; 
      } catch (RemoteException e) { 
       Log.e(LOG_TAG, "Remote Exception while starting Ranging", e); 
      } 
     } 
    } 

    private void stopScan() { 
     try { 
      beaconManager.stopMonitoringBeaconsInRegion(region); 
      beaconManager.stopRangingBeaconsInRegion(region); 
      isScanning = false; 
     } catch (RemoteException e) { 
      Log.e(LOG_TAG, "Remote Exception while stoping Ranging", e); 
     } 
     Log.i(LOG_TAG, "Stopping scanning"); 
    } 

    SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() { 
     public void onSharedPreferenceChanged(SharedPreferences sp, String key) { 
      if (key.equalsIgnoreCase(Constants.SharedPreferences.IS_VISIBILITY_ON) && getActivity() != null) { 
       if (sp.getBoolean(Constants.SharedPreferences.IS_VISIBILITY_ON, false)) { 

        Log.i(LOG_TAG, "Visibility turned ON"); 
        refreshScan(); 
       } else { 
        Log.i(LOG_TAG, "Visibility turned off"); 
        visbilityOffTasks(); 
       } 
      } 
     } 
    }; 

    private void visbilityOffTasks() { 
     stopScan(); 
     deviceToBeaconMap.clear(); 
    } 

    int onLostTimeoutMillis = 15000; 

    private void setOnLostRunnable() { 
     removeHandler.postDelayed(removeLostDevices, onLostTimeoutMillis); 
    } 

    private static final Handler removeHandler = new Handler(Looper.getMainLooper()); 
    Runnable removeLostDevices = new Runnable() { 
     @Override 
     public void run() { 
      long time = System.currentTimeMillis(); 
      Iterator<Map.Entry<String, Beacon>> itr = deviceToBeaconMap.entrySet().iterator(); 
      while (itr.hasNext()) { 
       Beacon beacon = itr.next().getValue(); 
       if (beacon != null && !beacon.deviceAddress.equalsIgnoreCase("default")) 
        if ((time - beacon.lastSeenTimestamp) > onLostTimeoutMillis) { 
         itr.remove(); 
         if (BuildConfig.DEBUG) 
          Log.d(LOG_TAG, "Removing beacon " + beacon.deviceAddress + " Time is " + (time - beacon.lastSeenTimestamp)); 
        } 
      } 
      removeHandler.postDelayed(this, onLostTimeoutMillis); 
     } 
    }; 


} 

Вот журналы, которые я наблюдал для сканирования. Даже после того, как сканирование маяков остановлено, они продолжают появляться.

12-25 22:27:59.103 30207-30207/com.robocats.main I/BlankFragment: Visibility turned ON 
12-25 22:27:59.104 30207-30207/com.robocats.main I/BlankFragment: Starting scanning 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:27:59.105 30207-30207/com.robocats.main I/BlankFragment: State of region changed 0 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: State of region changed 1 
12-25 22:28:00.061 30207-2969/com.robocats.main I/BlankFragment: In beacon region 
12-25 22:28:09.515 30207-30207/com.robocats.main D/BlankFragment: Removing beacon 0C:F3:EE:09:3A:77 Time is 15036 
12-25 22:28:09.642 30207-30207/com.robocats.main D/BlankFragment: Removing beacon 0C:F3:EE:09:3A:77 Time is 15161 
12-25 22:28:13.497 30207-3224/com.robocats.main D/BlankFragment: New Beacon added 6bd54ac521c218b8f418000000000073 DeviceAddress 0C:F3:EE:09:3A:77 
12-25 22:28:13.510 30207-3224/com.robocats.main D/BlankFragment: New Beacon added 6bd54ac521c218b8f418000000000073 DeviceAddress 0C:F3:EE:09:3A:77 
12-25 22:28:19.086 30207-3381/com.robocats.main D/BlankFragment: New Beacon added 2f234454f4911ba9ffa100000d5181da DeviceAddress 0C:F3:EE:09:3C:63 
12-25 22:28:19.096 30207-3381/com.robocats.main D/BlankFragment: New Beacon added 2f234454f4911ba9ffa100000d5181da DeviceAddress 0C:F3:EE:09:3C:63 
12-25 22:28:22.886 30207-30207/com.robocats.main I/BlankFragment: Visibility turned off 
12-25 22:28:22.887 30207-30207/com.robocats.main I/BlankFragment: Stopping scanning 
12-25 22:28:23.586 30207-3468/com.robocats.main D/BlankFragment: New Beacon added 2f234454f4911ba9ffa100000d5181da DeviceAddress 0C:F3:EE:09:3C:63 
12-25 22:28:23.589 30207-3468/com.robocats.main D/BlankFragment: New Beacon added 4b3833f4b99a463283e84bfcc601a926 DeviceAddress 48:59:02:49:FA:3F 
12-25 22:28:24.706 30207-3483/com.robocats.main D/BlankFragment: New Beacon added 6bd54ac521c218b8f418000000000073 DeviceAddress 0C:F3:EE:09:3A:77 

По какой-то причине, я вижу, что код внутри onBeaconServiceConnect() работает в два раза. Это может быть причиной. Позвольте мне знать, почему это могло произойти.

+0

Код выглядит нормально. Вы говорите, что продолжаете получать разнообразные обратные вызовы, несмотря на то, что вы остановитесь? Добавление строки журнала в диапазон обратного вызова и добавление выдержки из LogCat может оказаться полезным для выяснения того, что происходит. – davidgyoung

+0

Да, я получаю диапазон обратных вызовов даже после остановки диапазона. Написал LogCat, чтобы помочь вам лучше понять. Взгляни, пожалуйста. –

ответ

1

Я считаю, что проблема вызвана жизненным циклом Android, создающим несколько копий BlankFragment. Каждый раз, когда BlankFragment создается, метод onCreate вызывается, а код привязывается к службе сканирования и начинает масштабирование. Поскольку множественные фрагменты создаются без вызова onDestroy, вы получаете одновременно несколько экземпляров. Когда вызывается stopScan, он останавливается только для последнего созданного экземпляра фрагмента.

Одним из решений было бы остановить ранжирование и мониторинг, а затем отвязать, когда фрагмент исчезнет из поля зрения.

+0

Я думаю, вы правильно определили проблему. Я попробовал привязку к службам сканирования в onResume(), а затем прекратил ранжирование, мониторинг и отключение в onPause(), так что каждый раз, когда фрагмент выходит из поля зрения, он не привязан. Но это не помогает. Вероятно, это связано с тем, что я использую FragmentPagerAdapter в действии для создания фрагментов, содержащих ссылки на предыдущие копии. Так или иначе, он создает новые копии каждый раз, когда создается активность, и все еще удерживает старшие. Мне придется еще больше разобраться, чтобы понять проблему. Благодаря! –

+0

Далее я понял, что проблема повторяется, когда я выхожу из приложения (операция, содержащая BlankFragment, если быть точным), а затем снова ее открывать. Раньше я использовал BluetoothLeScanner для одной задачи и управлял жизненным циклом таким же образом, чтобы сканирование останавливалось, когда фрагмент больше не отображается. Он отлично работал и не отображал проблем, которые отмечаются при использовании Android Beacon Library. Можете ли вы рассказать о различиях в обоих способах сканирования? –

+0

Я не уверен, почему у вас не было подобных проблем с BluetoothLeScanner. Чтобы сделать фрагмент BeaconConsumer и выполнить эту работу, вам может потребоваться вручную сделать вызов, чтобы остановить каждый фрагмент от сканирования, когда он выходит из поля зрения. Однако, я думаю, что более простой способ сделать это - сделать Activity BeaconConsumer или даже POJO, чья ссылка принадлежит Activity. – davidgyoung