Вывод найденных и сопряженных Bluetooth устройств в ListView, дублирование устройств в списке
я новичок в Android разработке. Возникла проблема вывода bluetooth устройств в ListView. Суть такова, что при запуске приложения выводится список уже сопряженных устройств в ListView, а затем по нажатию кнопки в соседний ListView выводится список найденных устройств. В общем подобно обычному меню bluetooth в настройках.
Изначально все выводилось в один ListView, но потом было решено разделить блоки и из-за этого все окончательно в голове запуталось (я новичок, поэтому листАдаптеры + BT API + тд.тп. вместе даются довольно тяжело). Я же правильно понимаю, что я могу использовать один адаптер для двух списков, т.к. они состоят из одних и тех же элементов?
Помимо этого еще есть проблема дублирования устройств в списке, причем некоторые по несколько раз, предварительная очистка списка не работает, они дублируются по ходу поиска. Скорее всего проблема в самом алгоритме поиска.
На код не ругайтесь, мой первый проект, дальше думаю разбить по разным папкам и файлам
Код MainActivity:
package com.example.bttest;
public class MainActivity extends AppCompatActivity implements
CompoundButton.OnCheckedChangeListener,
AdapterView.OnItemClickListener,
View.OnClickListener {
private static final int REQUEST_ENABLE_BT = 1; // Включение BT
public static final int BT_FOUND = 3; // Найденные BT устройства
private static final int REQUEST_CODE_LOCATION = 4; //Данные о местоположении
private Switch btSwitch; // Switch
private LinearLayout deviceListFrame; // Фрейм с устоойствами
private ListView bondedDeviceList; // Список найденных устройств
private ListView foundDeviceList; // Список сопряженных устройств
private Button btnStartSearch; // Кнопка "поиск"
private BluetoothAdapter bluetoothAdapter;
private ListAdapter listAdapter;
private ArrayList<BluetoothDevice> foundBluetoothDevices; // Массив найденных устройств
private ArrayList<BluetoothDevice> bondedBluetoothDevices; // Массив сопряженных устройств
private TextView myDeviceInfo; // Инфо об устройстве пользователя
private String myDeviceName; // Имя устройства пользователя
private String myDeviceAddress; // Адрес устройства пользователя
@SuppressLint("HardwareIds")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btSwitch = findViewById(R.id.switch_bt_on_off); // Switch для вкл/выкл BT
deviceListFrame = findViewById(R.id.device_list); // Фрейм с устройствами [обертка]
bondedDeviceList = findViewById(R.id.lv_bt_devices_bonded); // Список сопряженных устройств
foundDeviceList = findViewById(R.id.lv_bt_devices_found); // Список найденных устройств
btnStartSearch = findViewById(R.id.btn_startSearch);
myDeviceInfo = findViewById(R.id.tv_my_device_info); // Инфо о моем устройстве
btSwitch.setOnCheckedChangeListener(this);
bondedDeviceList.setOnItemClickListener(this);
btnStartSearch.setOnClickListener(this);
foundBluetoothDevices = new ArrayList<>();
bondedBluetoothDevices = new ArrayList<>();
bondedDeviceList.setAdapter(listAdapter);
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mReceiver, filter);
IntentFilter searchFilter = new IntentFilter();
searchFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
searchFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
searchFilter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(searchReciever, searchFilter);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth не поддерживается устройством", Toast.LENGTH_SHORT).show();
finish();
}
if (bluetoothAdapter.isEnabled()) {
myDeviceName = bluetoothAdapter.getName();
myDeviceAddress = bluetoothAdapter.getAddress();
myDeviceInfo.setText(myDeviceName + "\n" + myDeviceAddress);
showDeviceList();
btSwitch.setChecked(true);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
unregisterReceiver(searchReciever);
}
@Override
public void onClick(View v) {
if (v.equals(btnStartSearch)){
startSearch();
}
}
private void startSearch() {
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
} else {
accessLocationPermission();
bluetoothAdapter.startDiscovery();
}
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.equals(btSwitch)) {
enableBt(isChecked);
if (!isChecked) {
hideDeviceList();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK && bluetoothAdapter.isEnabled()) {
showDeviceList();
setListAdapter(BT_FOUND);
}
else if (resultCode == RESULT_CANCELED) {
btSwitch.setChecked(false);
}
}
}
private void showDeviceList() {
deviceListFrame.setVisibility(View.VISIBLE);
}
private void hideDeviceList() {
deviceListFrame.setVisibility(View.GONE);
}
private void enableBt(boolean flag) {
if (flag) {
Intent btOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(btOn, REQUEST_ENABLE_BT);
}
else {
bluetoothAdapter.disable();
}
}
private void setListAdapter(int type) {
foundBluetoothDevices.clear();
bondedBluetoothDevices = getBondedBtDevices();
listAdapter = new ListAdapter(this, foundBluetoothDevices);
listAdapter = new ListAdapter(this, bondedBluetoothDevices);
bondedDeviceList.setAdapter(listAdapter);
foundDeviceList.setAdapter(listAdapter);
}
private ArrayList<BluetoothDevice> getBondedBtDevices() {
Set<BluetoothDevice> deviceSet = bluetoothAdapter.getBondedDevices();
ArrayList<BluetoothDevice> tmpArrayList = new ArrayList<>();
if (deviceSet.size() > 0) {
for (BluetoothDevice device: deviceSet) {
tmpArrayList.add(device);
}
}
return tmpArrayList;
}
private final BroadcastReceiver searchReciever = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
btnStartSearch.setText("Остановить");
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
btnStartSearch.setText("Начать поиск");
break;
case BluetoothDevice.ACTION_FOUND:
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null) {
foundBluetoothDevices.add(device);
listAdapter.notifyDataSetChanged();
}
break;
}
}
};
/**
* Слушатель состояния Bluetooth
**/
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
btSwitch.setChecked(false);
break;
case BluetoothAdapter.STATE_TURNING_OFF:
// Turning Bluetooth off...
break;
case BluetoothAdapter.STATE_ON:
btSwitch.setChecked(true);
break;
case BluetoothAdapter.STATE_TURNING_ON:
// Turning Bluetooth on...
break;
}
}
}
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_LOCATION:
if (grantResults.length > 0) {
for (int gr: grantResults) {
if (gr != PackageManager.PERMISSION_GRANTED) {
return;
}
}
}
break;
default:
return;
}
}
/**
*Запрос на разрешение получения данных о местоположении (6.0)
**/
private void accessLocationPermission() {
int accessCoarseLocation = this.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION);
int accessFineLocation = this.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION);
List<String> listRequestPermission = new ArrayList<String>();
if (accessCoarseLocation != PackageManager.PERMISSION_GRANTED) {
listRequestPermission.add(android.Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (accessFineLocation != PackageManager.PERMISSION_GRANTED) {
listRequestPermission.add(android.Manifest.permission.ACCESS_FINE_LOCATION);
}
if (!listRequestPermission.isEmpty()) {
String[] strRequestPermission = listRequestPermission.toArray(new String[listRequestPermission.size()]);
this.requestPermissions(strRequestPermission, REQUEST_CODE_LOCATION);
}
}
}
Код ListAdapter:
public class ListAdapter extends BaseAdapter {
private static final int RESOURCE_LAYOUT = R.layout.list_item;
private ArrayList<BluetoothDevice> bluetoothDevices;
private LayoutInflater inflater;
public ListAdapter(Context context, ArrayList<BluetoothDevice> bluetoothDevices) {
this.bluetoothDevices = bluetoothDevices;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return bluetoothDevices.size();
}
@Override
public Object getItem(int position) {
return getItem(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = inflater.inflate(RESOURCE_LAYOUT, parent, false);
BluetoothDevice device = bluetoothDevices.get(position);
if (device != null) {
((TextView) view.findViewById(R.id.device_name)).setText(device.getName());
((TextView) view.findViewById(R.id.device_address)).setText(device.getAddress());
if (device.getBondState() == 12) {
((ImageView) view.findViewById(R.id.icon_bound)).setImageResource(R.drawable.ic_bluetooth_bounded);
}
else if (device.getBondState() == 10) {
((ImageView) view.findViewById(R.id.icon_bound)).setImageResource(R.drawable.ic_bluetooth_no_bounded);
}
}
return view;
}
}
UPD:
Вопрос с выводом в ListView решил просто создав такой же адаптер для второго списка, хотя в принципе почти получилось оба списка заполнять одним адаптером, но видимо были кое-какие конфликты между ними из-за чего иногда один из списков не заполнялся (уверен что можно обойтись одним адаптером, но пока туповат чтобы это нормально реализовать).
Вопрос с дублированием решился добавлением дополнительной проверки (код в комментарии)