使用 altBeacon 库在 Android 中未显示所有信标

Posted

技术标签:

【中文标题】使用 altBeacon 库在 Android 中未显示所有信标【英文标题】:All beacons are not shown in Android using altBeacon library 【发布时间】:2015-03-13 22:11:29 【问题描述】:

我正在使用AltBEacon android library 开发适用于 Android 设备的 iBeacon 应用。我正在扫描信标,但是,只找到了四分之二的信标(有时是 1/4)。

我将mBeaconManager.setForegroundScanPeriod(5000l); 增加到 5 秒,但结果仍然相同。我不确定我用于绑定详细信息以查看的CustomAdapter 是否错误或问题与移动设备有关(我使用的是Galaxy Note II - Android 4.4.2 (KitKat))? 谁能找到我的错误?

另一个问题是从设备到信标的距离计算返回不正确(当我距离大约 0.5 米时,它返回 3-6 米之间)

我做错了什么?

注意:我已经检查了 Beacon 的 UUID、Major、Minors 是否有任何错误。我增加了扫描时间。这些都不起作用。

这是开始监控和测距的 Fragment:

public class FragmentScanBeacons extends Fragment implements BeaconConsumer

    public static Region mRegion = new Region("Server", Identifier.parse("Here is my UUID"), null, null);
    private BeaconManager mBeaconManager;

    private BeaconBaseAdapter beaconBaseAdapter;

    private ListView beaconsListLv;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        mBeaconManager = BeaconManager.getInstanceForApplication(getActivity());

        //BEACON PARSER
        mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
        //mBeaconManager.debug = true;
        beaconBaseAdapter = new BeaconBaseAdapter(getActivity());
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

        View view = inflater.inflate(R.layout.fragment_beacons, container, false);

        //UI
        beaconsListLv = (ListView) view.findViewById(R.id.beaconsListView);

        //Set Adapter
        beaconsListLv.setAdapter(beaconBaseAdapter);

        //Check for bluetooth and Scan for Beacon
        verifyBluetooth();

        //Start Monitoring and Ranging
        mBeaconManager.bind(this);

        return view;
    

    @Override
    public void onResume() 
        super.onResume();
        if(mBeaconManager.isBound(this))
            mBeaconManager.setBackgroundMode(false);
        
    

    @Override
    public void onPause() 
        super.onPause();
        if(mBeaconManager.isBound(this))
            mBeaconManager.setBackgroundMode(true);
        
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        mBeaconManager.unbind(this);
    

    @Override
    public void onBeaconServiceConnect() 
        try 

            //Scan lasts for SCAN_PERIOD time
            mBeaconManager.setForegroundScanPeriod(1000l);
            //mBeaconManager.setBackgroundScanPeriod(0l);

            //Wait every SCAN_PERIOD_INBETWEEN time
            mBeaconManager.setForegroundBetweenScanPeriod(0l);

            //Update default time with the new one
            mBeaconManager.updateScanPeriods();
        
        catch (RemoteException e)
            e.printStackTrace();
        

        //Set Monitoring
        mBeaconManager.setMonitorNotifier(new MonitorNotifier() 
            @Override
            public void didEnterRegion(Region region) 
                Log.d("TEST", "ENTERED beacon region");

                //Start Raning as soon as you detect a beacon
                try 
                    mBeaconManager.startRangingBeaconsInRegion(mRegion);
                
                catch (RemoteException e) 
                    e.printStackTrace();
                
            

            @Override
            public void didExitRegion(Region region) 
                Log.d("TEST", "EXITED beacon region");
            

            @Override
            public void didDetermineStateForRegion(int state, Region region) 
                Log.d("TEST", "SWITCHED from seeing/not seeing beacon to state " + state);
            
        );

        //Set Ranging
        mBeaconManager.setRangeNotifier(new RangeNotifier() 
            @Override
            public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) 
                if (beacons != null && beacons.size() > 0) 
                    getActivity().runOnUiThread(new Runnable() 
                        @Override
                        public void run() 
                            beaconBaseAdapter.initAll(beacons);
                        
                    );
                
            
        );

        try 
            //Start Monitoring
            mBeaconManager.startMonitoringBeaconsInRegion(mRegion);
        
        catch (RemoteException e) 
            e.printStackTrace();
        

    

    @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 mode) 
        return getActivity().bindService(intent, serviceConnection, mode);
    

这是自定义适配器:

public class BeaconBaseAdapter extends BaseAdapter 

    private Context myContext;

    private LayoutInflater inflater;

    public static ArrayList<Beacon> beacons;

    public BeaconBaseAdapter(Context context) 
        this.myContext = context;
        this.inflater = LayoutInflater.from(context);
        this.beacons = new ArrayList<Beacon>();
    

    public void initAll(Collection<Beacon> newBeacons) 
        this.beacons.clear();
        this.beacons.addAll(newBeacons);
        notifyDataSetChanged();
    

    @Override
    public int getCount() 
        return beacons.size();
    

    @Override
    public Beacon getItem(int position) 
        return beacons.get(position);
    

    @Override
    public long getItemId(int position) 
        return position;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 

        if (convertView == null) 
            convertView = inflater.inflate(R.layout.beacon_list_row, null);
            convertView.setTag(new ViewHolder(convertView));
        

        bind(getItem(position), position, convertView);
        return convertView;
    


    private void bind(Beacon beacon, int position, View view) 
        ViewHolder holder = (ViewHolder) view.getTag();

        holder.manufacturerTextView.setText("Manufacturer: " + beacon.getManufacturer());
        holder.idOneTextView.setText("UUID: " + beacon.getId1());
        holder.idTwoTextView.setText("Major: " + beacon.getId2());
        holder.idThreeTextView.setText("Minor: " + beacon.getId3());
        holder.txPowerTextView.setText("TX-Power: " + beacon.getTxPower());
        holder.rssiTextView.setText("RSSI: " + beacon.getRssi());
        holder.distanceTextView.setText(String.format("DISTANCE: (%.2f m)", beacon.getDistance()));
        holder.nameTextView.setText("Bluetooth Name: " + beacon.getBluetoothName());
        holder.addressTextView.setText("Bluetooth Adrs: " + beacon.getBluetoothAddress());
    

    static class ViewHolder 
        final TextView nameTextView;
        final TextView manufacturerTextView;
        final TextView idOneTextView;
        final TextView idTwoTextView;
        final TextView idThreeTextView;
        final TextView txPowerTextView;
        final TextView rssiTextView;
        final TextView distanceTextView;
        final TextView addressTextView;

        ViewHolder(View view) 
            nameTextView = (TextView) view.findViewWithTag("name");
            manufacturerTextView = (TextView) view.findViewWithTag("manufacturer");
            idOneTextView = (TextView) view.findViewWithTag("id_one");
            idTwoTextView = (TextView) view.findViewWithTag("id_two");
            idThreeTextView = (TextView) view.findViewWithTag("id_three");
            txPowerTextView = (TextView) view.findViewWithTag("tx_power");
            rssiTextView = (TextView) view.findViewWithTag("rssi");
            distanceTextView = (TextView) view.findViewWithTag("distance");
            addressTextView = (TextView) view.findViewWithTag("address");
        
    

【问题讨论】:

您是否正在使用其他应用程序检测这些信标?在我开发过程中,我有一半的信标没电了…… 是的,我用ios设备检查了它们,都找到了。实际上 android 设备它也可以找到所有但不是一次捕获。有时它捕获 2,有时捕获 3。在 logcat 上有一个 onScanResult(),有时它会记录 3 个设备,但在我的 ListView 上只有 2 个被绑定 所有信标都来自同一制造商吗?我遇到了不同制造商的问题,必须找出不同的布局来添加到信标解析器列表中 @Álvaro Pérez Soria 是的,它们都来自同一个制造商。 【参考方案1】:

一些想法:

    尝试使用现成的信标检测程序,如 Locate,它在后台使用相同的 Android 信标库。如果程序可靠地检测到您的信标,则可能是您提到的自定义代码中的问题。

    确保您的信标传输频率足够高。基线传输频率为 10 Hz,但具有默认设置的库将可靠地拾取至少传输 1 Hz 的信标。如您所描述的那样增加mBeaconManager.setForegroundScanPeriod(); 应该会有所帮助,但如果信标仅以 0.1 Hz 传输,那么您仍然会遇到您所描述的问题。

    某些 Android 设备具有组合的 Wi-Fi/蓝牙芯片,这会阻止这两个无线电同时可靠地运行。尝试禁用 Wi-Fi,看看是否会得到相同的结果。

【讨论】:

那个确切的程序不是开源的,但它有一个 UI 更简单的版本:github.com/AltBeacon/android-beacon-library-reference。此版本仅显示检测到的第一个信标,但修改它以显示检测到的每个信标很简单。 您在参考应用程序中使用的是哪个版本的 Android 信标库?您下载的 Locate 应用是上周使用 2.1-beta1 版本的 Android Beacon Library 构建的。如果您使用的是这个版本的库,那么距离估计应该是相同的。 如果您希望以一致的排序顺序获得一致的可见信标列表,您需要维护自己的列表,在发现信标时将其添加到列表中,并在未发现时将其从列表中删除看了几秒。然后,您可以在显示列表之前按所需标准(例如按标识符)对列表进行排序。您必须在自定义代码中执行此操作,因为库不会为您执行此操作。 如果您使用来自使用不同布局的制造商的信标,则只需添加具有自定义信标布局的新 BeaconParser。所有符合 iBeacon 布局的信标都可以使用相同的解析器。 不幸的是,不,因为没有办法设置标准的信标标识符。见这里:***.com/a/20766229/1461050【参考方案2】:

好的,我终于解决了。我根据信标MAC address订购。所以而不是:

public void initAll(Collection<Beacon> newBeacons) 
    this.beacons.clear();
    this.beacons.addAll(newBeacons);

我做到了:

public void initAll(Collection<Beacon> newBeacons) 

    this.beacons.clear();
    this.beacons.addAll(newBeacons);

    //Sort
    Collections.sort(this.beacons, new Comparator<Beacon>() 
        @Override
        public int compare(Beacon b1, Beacon b2) 
            String mac1 = b1.getBluetoothAddress();
            String mac2 = b2.getBluetoothAddress();

            return mac1.compareTo(mac2);
        
    );

【讨论】:

以上是关于使用 altBeacon 库在 Android 中未显示所有信标的主要内容,如果未能解决你的问题,请参考以下文章

Android 如何使用 Android Studio 和 gradle 创建包含 Altbeacon 库的库(jar)

使用 AltBeacon 库以 CoreBluetooth 格式做广告

当我使用我的 Android 设备作为使用 AltBeacon 的 ibeacon 时找不到 CoreBluetooth

Android中的Altbeacon扫描仪特定UUID

在 Android 8 之前的应用程序重新启动后,AltBeacon 未检测到 iBeacon

altbeacon 参考应用程序和多个退出/进入调用