Android 4.3:如何连接到多个低功耗蓝牙设备? [英] Android 4.3: How to connect to multiple Bluetooth Low Energy devices?

查看:154
本文介绍了Android 4.3:如何连接到多个低功耗蓝牙设备?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任务:

我正在开发一个Android应用程序,该应用程序需要同时连接到多个(相同的,可以通过其ID区分)BLE芯片设备,以便发送和接收更新.我已经在Google的官方网页上使用了这些教程:

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

这帮助我创建了DeviceScanActivity Java类,该类使我可以扫描并列出所有附近的可用BLE设备,这与当前大多数此类应用程序类似.我还发现,最多可以将7个外部从站同时连接到同一主设备.但是,对于我来说,实现这种沟通仍然不清楚.有用的链接是:

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:如何连接到多个低功耗蓝牙设备

但是,它没有为我提供足够的详细信息来了解这种实现的工作原理.

However, it does not provide enough detail for me to understand how such an implementation works.

一段时间以来,我一直在研究此主题,但找不到任何示例实现.我知道这个问题已经被问过很多次了,但是似乎没有任何有效的解决方案/演示可以在线获取,以使事情对我来说更加清晰.如果有人可以向我提出一个资源/工作解决方案,我将不胜感激,该解决方案将详细说明修改现有Java类以实现此功能所必需的步骤.

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;
    }
}

当前信息:

  • 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目标表示形式:

我的想法是我的5.1.1 Android Nexus 7设备最多可以连接到5个BLE芯片从站并发送/接收更新.

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.

推荐答案

我已经在Android中使用两个设备完成了此操作. 首先,根据我的经验,拆分代码会更好.就我而言,我在扫描过程中使用了一项服务.使用广播接收器,我已将找到的设备对象发送给了主要活动.在一般的本活动中,只有ui东西和我的Servicenavigation完成了.当我的主要活动接收到Bluetooth设备对象时,我将此对象传输到一个单独的服务,在该服务中仅进行了蓝牙通信,并与另一个Broadcastreceiver一起将接收到的数据发送回我的mainactivity以显示值. 如果要连接多个设备,则可以使用与使用一台设备相同的方式来使用此模式.在LeScan Callback的扫描仪服务中,检查找到的设备的Macadress.我已经为要连接的所有Mac地址疯狂地使用了字符串数组.当我找到一个设备时,我已将其从阵列中删除;找到所有想要的设备后,您可以停止整个服务. 此外: 我的经验是,您不应约束您的服务.最好手动启动和停止服务.当我想破坏我的绑定服务时,连接仍然处于活动状态,而当再次连接时,蓝牙表现异常,或者我无法找到Ble服务器设备,因为它在内部仍处于绑定状态.

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.

这篇关于Android 4.3:如何连接到多个低功耗蓝牙设备?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆