2015-10-05 2 views
1

Это глупый вопрос, но у меня есть код, который дает мне список маяков с их именами, адресами, uuids, майорами и несовершеннолетними в TextView. Я вычисляю uuid, основные и второстепенные значения (в коде ниже). И когда я устанавливаю эти три значения в TextView, они меняются с другими значениями маяка. Поэтому мой вопрос заключается в том, как я устанавливаю надлежащую uuid, основную и второстепенную ценность для правильного маяка?Android. Как настроить значение маяка UUID для правильного текстового просмотра?

Ссылка на примере: http://i.stack.imgur.com/vlepI.jpg

У меня два маяков. Имена и адреса правильны, но поскольку вы можете видеть uuid, основные второстепенные совпадают, и во время сканирования они продолжают менять значения маяков.

Код приведен ниже.

DeviceScanActivity

public class DeviceScanActivity extends ListActivity { 

private LeDeviceListAdapter mLeDeviceListAdapter; 
private BluetoothAdapter mBluetoothAdapter; 
private boolean mScanning; 
private Handler mHandler; 
private static final int REQUEST_ENABLE_BT = 1; 
private static final long SCAN_PERIOD = 10000; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    getActionBar().setTitle(R.string.title_devices); 
    mHandler = new Handler(); 

    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
     Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); 
     finish(); 
    } 

    final BluetoothManager bluetoothManager = 
      (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
    mBluetoothAdapter = bluetoothManager.getAdapter(); 

    if (mBluetoothAdapter == null) { 
     Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); 
     finish(); 
     return; 
    } 
} 
@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
     case R.id.menu_scan: 
      mLeDeviceListAdapter.clear(); 
      scanLeDevice(true); 
      break; 
     case R.id.menu_stop: 
      scanLeDevice(false); 
      break; 
    } 
    return true; 
} 

@Override 
protected void onResume() { 
    super.onResume(); 

    if (!mBluetoothAdapter.isEnabled()) { 
     if (!mBluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 
     } 
    } 

    mLeDeviceListAdapter = new LeDeviceListAdapter(); 
    setListAdapter(mLeDeviceListAdapter); 
    scanLeDevice(true); 
} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    // User chose not to enable Bluetooth. 
    if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { 
     finish(); 
     return; 
    } 
    super.onActivityResult(requestCode, resultCode, data); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    scanLeDevice(false); 
    mLeDeviceListAdapter.clear(); 
} 

@Override 
protected void onListItemClick(ListView l, View v, int position, long id) { 
    final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position); 
    if (device == null) return; 
    //final Intent intent = new Intent(this, DeviceControlActivity.class); 

    if (mScanning) { 
     mBluetoothAdapter.stopLeScan(mLeScanCallback); 
     mScanning = false; 
    } 
    //startActivity(intent); 
} 

private void scanLeDevice(final boolean enable) { 
    if (enable) { 
     // Stops scanning after a pre-defined scan period. 
     mHandler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       mScanning = false; 
       mBluetoothAdapter.stopLeScan(mLeScanCallback); 
       invalidateOptionsMenu(); 
      } 
     }, SCAN_PERIOD); 

     mScanning = true; 
     mBluetoothAdapter.startLeScan(mLeScanCallback); 
    } else { 
     mScanning = false; 
     mBluetoothAdapter.stopLeScan(mLeScanCallback); 
    } 
    invalidateOptionsMenu(); 
} 

private class LeDeviceListAdapter extends BaseAdapter { 
    private ArrayList<BluetoothDevice> mLeDevices; 
    private LayoutInflater mInflator; 

    public LeDeviceListAdapter() { 
     super(); 
     mLeDevices = new ArrayList<BluetoothDevice>(); 
     mInflator = DeviceScanActivity.this.getLayoutInflater(); 
    } 

    public void addDevice(BluetoothDevice device) { 
     if(!mLeDevices.contains(device)) { 
      mLeDevices.add(device); 
     } 
    } 

    public BluetoothDevice getDevice(int position) { 
     return mLeDevices.get(position); 
    } 

    public void clear() { 
     mLeDevices.clear(); 
    } 

    @Override 
    public int getCount() { 
     return mLeDevices.size(); 
    } 

    @Override 
    public Object getItem(int i) { 
     return mLeDevices.get(i); 
    } 

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

    @Override 
    public View getView(int i, View view, ViewGroup viewGroup) { 
     ViewHolder viewHolder; 
     if (view == null) { 
      view = mInflator.inflate(R.layout.listitem_device, null); 
      viewHolder = new ViewHolder(); 
      viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address); 
      viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name); 
      viewHolder.deviceUUID = (TextView) view.findViewById(R.id.device_uuid); 
      viewHolder.deviceMajor = (TextView) view.findViewById(R.id.device_major); 
      viewHolder.deviceMinor = (TextView) view.findViewById(R.id.device_minor); 
      view.setTag(viewHolder); 
     } else { 
      viewHolder = (ViewHolder) view.getTag(); 
     } 

     BluetoothDevice device = mLeDevices.get(i); 
     final String deviceName = device.getName(); 
     if (deviceName != null && deviceName.length() > 0) 
      viewHolder.deviceName.setText(deviceName); 
     else 
      viewHolder.deviceName.setText(R.string.unknown_device); 
     viewHolder.deviceAddress.setText(device.getAddress()); 
     viewHolder.deviceUUID.setText(uuid); 
     viewHolder.deviceMajor.setText(major); 
     viewHolder.deviceMinor.setText(minor); 

     return view; 
    } 
} 

public String uuid; 
public int major_temp; 
public int minor_temp; 
public String major; 
public String minor; 


public static final char[] hexArray = "ABCDEF".toCharArray(); 
public static String bytesToHex(byte[] bytes) { 
    char[] hexChars = new char[bytes.length * 2]; 
    for (int j = 0; j < bytes.length; j++) { 
     int v = bytes[j] & 0xFF; 
     hexChars[j * 2] = hexArray[v >>> 4]; 
     hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
    } 
    return new String(hexChars); 
} 

public BluetoothAdapter.LeScanCallback mLeScanCallback = 
     new BluetoothAdapter.LeScanCallback() { 

    @Override 
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { 
     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       mLeDeviceListAdapter.addDevice(device); 
       mLeDeviceListAdapter.notifyDataSetChanged(); 
      } 
     }); 

     int startByte = 2; 
     boolean patternFound = false; 
     while (startByte <= 5) { 
      if ( ((int) scanRecord[startByte + 2] & 0xff) == 0x02 && //Identifies an iBeacon 
        ((int) scanRecord[startByte + 3] & 0xff) == 0x15) { //Identifies correct data length 
       patternFound = true; 
       break; 
      } 
      startByte++; 
     } 

     if (patternFound) { 
      byte[] uuidBytes = new byte[16]; 
      System.arraycopy(scanRecord, startByte+4, uuidBytes, 0, 16); 
      String hexString = bytesToHex(uuidBytes); 

       //Here is your UUID 
       uuid = hexString.substring(0,8) + "-" + 
         hexString.substring(8,12) + "-" + 
         hexString.substring(12,16) + "-" + 
         hexString.substring(16,20) + "-" + 
         hexString.substring(20,32); 

      major_temp = (scanRecord[startByte+20] & 0xff) * 0x100 + (scanRecord[startByte+21] & 0xff); 
      major = Integer.toString(major_temp); 
      minor_temp = (scanRecord[startByte+22] & 0xff) * 0x100 + (scanRecord[startByte+23] & 0xff); 
      minor = Integer.toString(minor_temp); 
      // TextView textView1 = (TextView) findViewById(R.id.device_uuid); 
      // textView1.setText(uuid+" Major: " + major + " Minor: " + minor); 


     } 

    } 

}; 

static class ViewHolder { 
    TextView deviceName; 
    TextView deviceAddress; 
    TextView deviceUUID; 
    TextView deviceMajor; 
    TextView deviceMinor; 
} 

}

и расположение файла:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:orientation="vertical" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content"> 
    <TextView android:id="@+id/device_name" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:textSize="24dp"/> 
    <TextView android:id="@+id/device_address" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:textSize="12dp"/> 
    <TextView android:id="@+id/device_uuid" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:textSize="12dp"/> 
    <TextView android:id="@+id/device_major" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:textSize="12dp"/> 
    <TextView android:id="@+id/device_minor" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:textSize="12dp"/> 
</LinearLayout> 
+0

Ничего себе. Ваш вопрос почти не имеет смысла. Пожалуйста, опубликуйте результат, который вы получаете, и ваш желаемый результат. – Andy

+0

Ссылка на пример: http://i.stack.imgur.com/vlepI.jpg У меня есть два маяка. Имена и адреса правильны, но поскольку вы можете видеть uuid, основные второстепенные совпадают, и во время сканирования они продолжают менять значения маяков. – DoeUS

ответ

1

Там проблема в том, как вы справляетесь маяки нашли. Просто внимательно посмотрите, где вы назначаете какое-либо значение для UUID, основного и второстепенного, и что входит в список.

В вашем LeScanCallback вы добавили все найденные устройства Bluetooth LE в адаптер списка. Вы добавляете их как BluetoothDevice, который является всего лишь универсальной моделью и ничего не знает о специфическом UUID iBeacon, майоре и младшем.

Затем вы выделяете UUID, майор и младший в переменные-члены класса. Это делается всегда, когда найденный BluetoothDevice признан iBeacon. В любое время вы храните только один комплект UUID, основного и младшего. Это всегда ценности последних iBeacon найдено.

Таким образом, вместо того, чтобы иметь список BluetoothDevices, вы можете создать простой класс, представляющий iBeacon с UUID, основным, второстепенным и, возможно, RSSI и TxPower, если вы хотите позже провести оценку расстояния. Затем в обратном вызове сканирования не добавьте BluetoothDevices в список, но добавьте iBeacons в конце кода проверки шаблона. Что-то вроде:

public BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { 

    @Override 
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { 
     /* Remove: 
     runOnUiThread(new Runnable() { 
     @Override 
      public void run() { 
       mLeDeviceListAdapter.addDevice(device); 
       mLeDeviceListAdapter.notifyDataSetChanged(); 
      } 
     }); 
     */ 
     int startByte = 2; 
     boolean patternFound = false; 
     while (startByte <= 5) { 
      if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 && //Identifies an iBeacon 
        ((int) scanRecord[startByte + 3] & 0xff) == 0x15) { //Identifies correct data length 
       patternFound = true; 
       break; 
      } 
      startByte++; 
     } 

     if (patternFound) { 
      byte[] uuidBytes = new byte[16]; 
      System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16); 
      String hexString = bytesToHex(uuidBytes); 

      //Here is your UUID 
      uuid = hexString.substring(0, 8) + "-" + 
        hexString.substring(8, 12) + "-" + 
        hexString.substring(12, 16) + "-" + 
        hexString.substring(16, 20) + "-" + 
        hexString.substring(20, 32); 

      major_temp = (scanRecord[startByte + 20] & 0xff) * 0x100 + (scanRecord[startByte + 21] & 0xff); 
      major = Integer.toString(major_temp); 
      minor_temp = (scanRecord[startByte + 22] & 0xff) * 0x100 + (scanRecord[startByte + 23] & 0xff); 
      minor = Integer.toString(minor_temp); 

      // Add: 
      IBeacon iBeacon = new IBeacon(uuid, major, minor); 
      runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        mLeDeviceListAdapter.addDevice(iBeacon); 
        mLeDeviceListAdapter.notifyDataSetChanged(); 
       } 
      }); 
     } 
    } 
} 

Затем измените список адаптер использовать объекты IBeacon и не BluetoothDevice объекты и исправить код в GetView(). На данный момент вы читаете UUID, основные и второстепенные из указанных переменных-членов, где они всегда имеют значения последнего найденного iBeonon.

Поэтому вместо этого прочитайте значения из списка mLeDevices, который теперь содержит объекты iBeacon. Что-то вроде:

@Override 
public View getView(int i, View view, ViewGroup viewGroup) { 
    ViewHolder viewHolder; 
    if (view == null) { 
     view = mInflator.inflate(R.layout.listitem_device, null); 
     viewHolder = new ViewHolder(); 
     viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address); 
     viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name); 
     viewHolder.deviceUUID = (TextView) view.findViewById(R.id.device_uuid); 
     viewHolder.deviceMajor = (TextView) view.findViewById(R.id.device_major); 
     viewHolder.deviceMinor = (TextView) view.findViewById(R.id.device_minor); 
     view.setTag(viewHolder); 
    } else { 
     viewHolder = (ViewHolder) view.getTag(); 
    } 

    BluetoothDevice device = mLeDevices.get(i); 
    final String deviceName = device.getName(); 
    if (deviceName != null && deviceName.length() > 0) { 
     viewHolder.deviceName.setText(deviceName); 
    } 
    else { 
     viewHolder.deviceName.setText(R.string.unknown_device); 
    } 
    viewHolder.deviceAddress.setText(device.getAddress()); 
    // Change these: 
    viewHolder.deviceUUID.setText(device.getUuid); 
    viewHolder.deviceMajor.setText(device.getMajor); 
    viewHolder.deviceMinor.setText(device.getMinor); 

    return view; 
} 

Затем нужно будет изменить AddDevice списка адаптеров для сравнения IBeacon объектов вместо объектов BluetoothDevice.

public void addDevice(IBeacon device) { 
    // This probably won't without some extra work:   
    if(!mLeDevices.contains(device)) { 
     mLeDevices.add(device); 
    } 
} 
+0

Я сделал все, что вы сказали в DeviceScanActivity. Я создал класс IBeacon с uuid, major, minor и get методы для получения значений в текстовом представлении. Но я получаю это на своем экране: [Снимок экрана] (http://i.stack.imgur.com/ElmMb.jpg). Для двух маяков это дает мне много позиций в моем списке, beacause каждый раз, когда приложение вычисляет uuid и т. Д., Это добавляет мне новое маяковое устройство в моем списке. Как я могу это исправить? – DoeUS

+0

Вам нужно будет сделать метод addDevice() для работы с объектами IBeacon. Возможно, лучший способ исправить это - переопределить методы класса equals() и hashCode() класса Object в новом классе IBeacon. Затем будут работать contains(), а также другие сравнения. Посмотрите на [how contains() works] (https://stackoverflow.com/questions/2642589/how-does-a-arraylists-contains-method-evaluate-objects) и [overriding equals()] (https://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java/27609#27609) –

+0

Я переопределяю метод equals() в своем новом Класс Ibeacon, и он отлично работает! Большое спасибо! – DoeUS