停止扫描信标:stopRangingBeaconsInRegion() 不工作

Stop scanning of beacons: stopRangingBeaconsInRegion() not working

我正在使用 Android 信标库扫描 Android 应用程序的 Eddystone 信标。我在连接信标服务后开始监控,然后在找到信标时开始测距。

我需要根据用户的选择停止扫描信标(停止监视和测距)。我正在使用

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

在我的 stopScan() 中停止扫描。但是测距并没有停止,尽管监控停止了。我做错了什么吗?

完整代码如下:

    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() 中的代码是 运行 两次。这可能是原因。让我知道为什么会发生这种情况。

我认为问题是由 Android 生命周期创建多个 BlankFragment 副本引起的。每次创建 BlankFragment 时,都会调用 onCreate 方法,并且代码会绑定到扫描服务并开始测距。因为在没有调用 onDestroy 的情况下创建了多个片段,所以您最终会同时遇到多个实例。调用 stopScan 时,它只会停止对最近创建的 Fragment 实例的测距。

一种解决方案是停止测距和监控,然后在片段离开视野时解除绑定。