问题
Task:
I am developing an Android application that will need to simultaneously connect to multiple (identical, that can be differentiated via their ID) BLE chip devices in order to send and receive updates. I have used the tutorials on Google's official web page:
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
This has helped me to create a DeviceScanActivity Java class that allows me to scan for and list all of the available BLE devices in close proximity, similarly to what most applications of this type currently do. I also found out that up to 7 external slaves can be connected to the same master device simultaneously. However, implementing this communication is still unclear for me. A useful link is:
Android 4.3: How to connect to multiple Bluetooth Low Energy devices
However, it does not provide enough detail for me to understand how such an implementation works.
I have been researching this topic for a while and was not able to find any example implementations. I am aware that this question has been asked a lot of times but there does not seem to be any working solution/ demo that is available online to make things more clear for me. I will appreciate it a lot if anyone can point me to a resource/ working solution that will explain in detail the steps that are necessary to modify my existing Java class in order to implement this functionality.
DeviceScanActivity.java:
import android.app.Activity;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
/**
* Activity for scanning and displaying available Bluetooth LE devices.
*/
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;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
private static final String CONFIG_FILE = "file";
private int _countClick = 0;
private boolean experimenterMode = false;
private String pairedDeviceAddress = "";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setTitle(R.string.title_devices);
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (!mScanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
}
return true;
}
@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;
case android.R.id.home:
//onBackPressed();
_countClick++;
if(_countClick>8)
{
toggleExperimenterMode();
}
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Restore preferences
SharedPreferences settings = getSharedPreferences(CONFIG_FILE, 0);
experimenterMode = settings.getBoolean("experimenterMode", false);
pairedDeviceAddress = settings.getString("pairedDeviceAddress", "");
// Initializes list view adapter.
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;
connectToDevice(device);
}
private void connectToDevice(BluetoothDevice device){
final Intent intent = new Intent(this, DeviceControlActivity.class);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
SharedPreferences settings = getSharedPreferences(CONFIG_FILE, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("pairedDeviceAddress", device.getAddress());
editor.commit();
startActivity(intent);
}
//---------------------------------------------------
private void scanLeDevice(final boolean enable) {
ProgressDialog progress;
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 void toggleExperimenterMode(){
_countClick=0;
experimenterMode = !experimenterMode;
SharedPreferences settings = getSharedPreferences(CONFIG_FILE, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("experimenterMode", experimenterMode);
editor.commit();
String t = experimenterMode ? "You are now in Experimenter mode":"You are now in User mode";
Toast.makeText(this, t, Toast.LENGTH_SHORT).show();
}
// Adapter for holding devices found through scanning.
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);
}
if (!experimenterMode && ! pairedDeviceAddress.isEmpty()) {
if (device.getAddress().equals(pairedDeviceAddress)) {
connectToDevice(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;
// General ListView optimization code.
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);
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());
return view;
}
}
// Device scan callback.
private 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();
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
}
Current Information:
- Android 4.3: How to connect to multiple Bluetooth Low Energy devices
- https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
- Does Android 4.3 support multiple BLE device connections?
- Ble multiple connection
- https://labs.hybris.com/2014/10/06/connecting-to-multiple-ble-devices/
- https://e2e.ti.com/support/wireless_connectivity/f/538/t/225935
All of these pages contain some directions, but they do not provide enough detail on how multiple connections can be implemented.
UI Target Representation:
The idea is that my 5.1.1 Android Nexus 7 device will be able to connect to at most 5 BLE chip slaves and send/receive updates.
回答1:
I've done this in Android with two devices. First in my experience it is much better to split your code. In my case, I used the a service for the scanning process. With a broadcastreceiver I've sent the found device Object to ma main activity. In this Activity in genereal only the ui stuff an my Servicenavigation is done. When my main activity revceived the Bluetoothdevice Object I transmit this Object to a seperate Service where only the Bluetoothcommunication is done and with another Broadcastreceiver I sent the received Data back to my mainactivity to display values. If you want to connect multiple devices, you can use this pattern the same way as you would do with one device. In the scanner service in you LeScan Callback you check the found devices for their Macadress. I've mad a String Array with all the Mac Adresses I want to connect to. When I found one I've deleted it from the Array and when you've found all the devices you want you can stop the whole service. In Addition: I've made the experience that you should not bind you service. it is better to start and stop your service manually. When I wanted to destroy my bound service pretty often the connection stayed alive an when connecting again my Bluetooth behaves weird or I can't find my Ble server device because internally it is still bound.
来源:https://stackoverflow.com/questions/31233087/android-4-3-how-to-connect-to-multiple-bluetooth-low-energy-devices