0

I'm trying to make a simple app that lists all the found Ibeacons in a ListView and changes the RSSI values according to the distance the user is from the beacons itself.

The app works fine, but the problem I'm having is that if a beacon is out of reach it does not get removed from the list. Any ideas on how to remove the item when the beacon isn't in range anymore?

I have the following code:

MainActivity.java:

public class MainActivity extends Activity implements BeaconConsumer {


    public ListView list;
    public BeaconAdapter adapter;
    public ArrayList<Beacon> arrayL = new ArrayList<>();
    public LayoutInflater inflater;
    public BeaconManager mBeaconManager;
    public boolean beaconPresent;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        list = (ListView)findViewById(R.id.lijst);
        mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
        mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
        mBeaconManager.setForegroundBetweenScanPeriod(100);

        mBeaconManager.bind(this);
        adapter = new BeaconAdapter();

        list.setAdapter(adapter);
        inflater =(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }





    public void onBeaconServiceConnect() {
        Region region = new Region("all-beacons-region", null, null, null);
        try {
            mBeaconManager.startRangingBeaconsInRegion(region);
        } catch (RemoteException e) {
            e.printStackTrace();
        }


        mBeaconManager.setRangeNotifier(new RangeNotifier() {

            @Override
            public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ArrayList<Beacon> allRangedBeacons = (ArrayList<Beacon>) beacons;
                        ArrayList<Beacon> newRangedBeacons = new ArrayList<>();
                        ArrayList<Beacon> cloneArraylistIBeacon = (ArrayList<Beacon>) arrayL.clone();
                        ArrayList<Beacon>nonRangedBeacons = new ArrayList<>();
                        int index = 0;
                        for (Beacon presentBeacons : cloneArraylistIBeacon) {
                             beaconPresent = false;
                            for (Beacon eachRangedBeacon : allRangedBeacons) {
                                if (presentBeacons.equals(eachRangedBeacon)) {
                                    arrayL.remove(index);
                                    arrayL.add(index, eachRangedBeacon);
                                  beaconPresent = true;
                                }
                                if(beaconPresent = false) {
                                    nonRangedBeacons.add(presentBeacons);
                                }
                            }
                            index++;
                        }
                        for (Beacon eachRangedBeacon : allRangedBeacons) {
                            beaconPresent = false;
                            for (Beacon presentBeacons : cloneArraylistIBeacon) {
                                if (eachRangedBeacon.equals(presentBeacons)) {
                                    beaconPresent = true;
                                }
                            }
                            if (!beaconPresent) {
                                newRangedBeacons.add(eachRangedBeacon);
                            }
                        }

                       arrayL.remove(nonRangedBeacons);
                        arrayL.addAll(newRangedBeacons);
                        adapter.notifyDataSetChanged();
                    }
                });
            }
        });
    }

    protected void onPause() {
        super.onPause();
        mBeaconManager.unbind(this);
    }

    private class BeaconAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            if (arrayL != null && arrayL.size() > 0) {
                return arrayL.size();
            } else {
                return 0;
            }
        }

        @Override
        public Beacon getItem(int position) {
            return arrayL.get(position);
        }

        @Override
        public long getItemId(int arg0) {
            return arg0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            holder = new ViewHolder(convertView = inflater.inflate(R.layout.tupple_monitoring, null));
            try {


                    holder.uuid.setText("UUID: " + arrayL.get(position).getId2());
                    holder.rssi.setText("RSSI: " + arrayL.get(position).getRssi());
                    holder.txpow.setText("TXPOW: " + arrayL.get(position).getTxPower());

                return convertView;
            }catch(Exception e) {
                e.printStackTrace();

            }
        return convertView;
        }
    }


    private class ViewHolder {

        private TextView uuid;
        private TextView rssi;
        private TextView txpow;

        public ViewHolder(View view) {
            uuid = (TextView)view.findViewById(R.id.BEACON_uuid);
            rssi = (TextView)view.findViewById(R.id.BEACON_rssi);
            txpow = (TextView)view.findViewById(R.id.BEACON_txpower);

            view.setTag(this);
        }
    }
}
brasay
  • 125
  • 1
  • 2
  • 14

2 Answers2

0

If you only want to display beacons in range, every time you receive a list of beacons simply change the adapter source list.

arrayL.clear();
arrayL.addAll(beacons);
adapter.notifyDataSetChanged();

To avoid jumping around if list items, maybe sort the beacons by their RSSI before displaying them.

Community
  • 1
  • 1
Capricorn
  • 2,061
  • 5
  • 24
  • 31
0

Because the Android Beacon Library already tracks the list of visible beacons and updates it in the ranging callback, you can simply refresh the whole list in your BeaconAdapter each time. Like this:

        @Override
        public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() { 
                    arrayL = new ArrayList<Beacon>(beacons);
                    adapter.notifyDataSetChanged();                   
                }
            });
        }
davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Hi, I've done this and the problem that keeps on surfacing is that the list keeps on flickering with items and then back to empty while scanning, even when the beacons are in an immediate range and should be found the list sometimes is empty and not all the beacons are added, any ideas on how to fix this problem? – brasay Sep 23 '15 at 13:55
  • Preventing this flickering is a bit tricky. One way is to create two `HashMap` objects keyed by `beacon.toString()`. The first `HashMap` contains timestamps of when the beacon was last detected. The second `HashMap` contains the beacons themselves. Each time you get a `didRangeBeaconsInRegion` callback, you add all the beacon detection times to the first HashMap and the beacons themselves to the second HashMap. Then you can loop through all of the timestamps in the first HashMap and if they are recent enough (say 10 seconds) add the corresponding beacon from the second HashMap to `arrayL` – davidgyoung Sep 23 '15 at 17:04