天天看點

Android BLE 藍牙程式設計(二)

大家中秋快樂啊~~哈哈,今天繼續工程項目吧!

上篇我們已經實作了藍牙裝置的掃描,本篇我們來通過list展示掃描到的裝置并

實作點選連接配接。

先貼出上篇的完整的MainActivity的方法:

package com.wbnq.shouhuan;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button saomiao , duanzhen , changzhen , buting , tingxia;
    private TextView jibu , dianliang , lianjiezhuangtai;

    BluetoothAdapter bluetoothAdapter;
    List<BluetoothDevice> deviceList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        //藍牙管理,這是系統服務可以通過getSystemService(BLUETOOTH_SERVICE)的方法擷取執行個體
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        //通過藍牙管理執行個體擷取擴充卡,然後通過掃描方法(scan)擷取裝置(device)
        bluetoothAdapter = bluetoothManager.getAdapter();


    }

    private void initView() {
        saomiao = (Button) findViewById(R.id.saomiao);
        duanzhen = (Button) findViewById(R.id.zhendong);
        changzhen = (Button) findViewById(R.id.changzhen);
        buting = (Button) findViewById(R.id.buting);
        tingxia = (Button) findViewById(R.id.tingxia);

        jibu = (TextView) findViewById(R.id.jibu);
        dianliang = (TextView) findViewById(R.id.dianliang);
        lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai);

        saomiao.setOnClickListener(this);
        duanzhen.setOnClickListener(this);
        changzhen.setOnClickListener(this);
        buting.setOnClickListener(this);
        tingxia.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.saomiao:
                //開始掃描前開啟藍牙
                Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(turn_on, 0);
                Toast.makeText(MainActivity.this, "藍牙已經開啟", Toast.LENGTH_SHORT).show();

                Thread scanThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i("TAG", "run: saomiao ...");
                        saomiao();
                    }
                });
                scanThread.start();

                break;
            case R.id.zhendong:

                break;
            case R.id.changzhen:

                break;
            case R.id.buting:

                break;
            case R.id.tingxia:

                break;

        }
    }

    public void saomiao(){
        deviceList.clear();
        bluetoothAdapter.startLeScan(callback);
    }

    //掃描回調
    public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState());

            //重複過濾方法,清單中包含不該裝置才加入清單中,并重新整理清單
            if (!deviceList.contains(bluetoothDevice)) {
                //将裝置加入清單資料中
                deviceList.add(bluetoothDevice);
            }

        }
    };
}      

View Code

這是上篇的,沒有在log下看到掃描消息的小夥伴看看出啥問題了吧~~

好了,第二篇正式開始。

先貼出來MyAdapter的代碼(這不是本節重點,請參閱前面關于adapter的寫法)

package com.wbnq.shouhuan;

import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by guwei on 16-9-2.
 */
public class MyAdapter extends BaseAdapter{

    public List<BluetoothDevice> mlist;
    private LayoutInflater mInflater;

    public MyAdapter(Context context , List<BluetoothDevice> list){
        mlist = list;
        mInflater = LayoutInflater.from(context);
    }

    //擷取傳入的數組大小
    @Override
    public int getCount() {
        return mlist.size();
    }

    //擷取第N條資料
    @Override
    public Object getItem(int i) {
        return mlist.get(i);
    }

    //擷取item id
    @Override
    public long getItemId(int i) {
        return i;
    }

    //主要方法
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = new ViewHolder();
        if(view == null){
            //首先為view綁定布局
            view = mInflater.inflate(R.layout.devices_item , null);
            viewHolder.name = (TextView) view.findViewById(R.id.bluetoothname);
            viewHolder.uuid = (TextView) view.findViewById(R.id.uuid);
            viewHolder.status = (TextView) view.findViewById(R.id.status);

            view.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder) view.getTag();
        }
        BluetoothDevice bd = mlist.get(i);
        viewHolder.name.setText(bd.getName());
        viewHolder.uuid.setText(bd.getAddress());

        //viewHolder.status.setText(R.string.noconnect);
        return view;
    }

    class ViewHolder{
        private TextView name , uuid , status;
    }
}      

View Code

item布局代碼 devices_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/bluetoothicon"
        android:layout_width="37dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_bluetooth_black_36dp" />

    <TextView
        android:id="@+id/bluetoothname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/bluetoothicon"
        android:text="name"
        android:textColor="#000000"
        android:textSize="19dp" />

    <TextView
        android:id="@+id/uuid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/bluetoothname"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp"
        android:layout_toRightOf="@id/bluetoothicon"
        android:text="uuid"
        android:textSize="15dp" />

    <TextView
        android:id="@+id/status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:layout_toRightOf="@id/bluetoothname"
        android:text=""
        android:textColor="#ff0000" />

</RelativeLayout>      

View Code

在布局檔案中添加一下listview控件

Android BLE 藍牙程式設計(二)

并且在MainActivity添加監聽。

然後在掃描回調中添加list.setAdapter(new MyAdapter(MainActivity.this , deviceList)); 

就可以順利的将得到的清單用list展示出來啦~~

//掃描回調
    public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState());

            //重複過濾方法,清單中包含不該裝置才加入清單中,并重新整理清單
            if (!deviceList.contains(bluetoothDevice)) {
                //将裝置加入清單資料中
                deviceList.add(bluetoothDevice);

                list.setAdapter(new MyAdapter(MainActivity.this , deviceList));
            }

        }
    };      

看下效果:點選掃描後

Android BLE 藍牙程式設計(二)

想要連接配接裝置就要在list的監聽事件中添加下面的方法:

這裡的bluetoothdevice就是用來存放每個item的内容的

上篇也說明了,想要連接配接裝置就要使用bluetoothDevice的connectGatt方法:

該方法包含三個參數:

參數一 : context 上下文 這裡傳 MainActivity即可

參數二: autoConnect 是否自動重連 一般填 false

參數三: gattcallback 是BluetoothGattCallback回調,該方法由系統提供,我們隻需要重寫方法即可

該方法的傳回值為bluetoothGatt類型。

//item 監聽事件
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                bluetoothDevice = deviceList.get(i);
                //連接配接裝置的方法,傳回值為bluetoothgatt類型
                bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback);
                lianjiezhuangtai.setText("連接配接" + bluetoothDevice.getName() + "中...");
            }
        });      

重寫gatt回調方法:

BluetoothGattCallback

private BluetoothGattCallback gattcallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    } ;      

View Code

我們這裡主要用到

onConnectionStateChange

onServicesDiscovered

onCharacteristicWrite

首先通過onConnectionStateChange擷取連接配接的狀态:

public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) {
            super.onConnectionStateChange(gatt, status, newState);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    String status;
                    switch (newState) {
                        //已經連接配接
                        case BluetoothGatt.STATE_CONNECTED:
                            lianjiezhuangtai.setText("已連接配接");

                            //該方法用于擷取裝置的服務,尋找服務
                 //bluetoothGatt.discoverServices();
                            break;
                        //正在連接配接
                        case BluetoothGatt.STATE_CONNECTING:
                            lianjiezhuangtai.setText("正在連接配接");
                            break;
                        //連接配接斷開
                        case BluetoothGatt.STATE_DISCONNECTED:
                            lianjiezhuangtai.setText("已斷開");
                            break;
                        //正在斷開
                        case BluetoothGatt.STATE_DISCONNECTING:
                            lianjiezhuangtai.setText("斷開中");
                            break;
                    }
                    //pd.dismiss();
                }
            });
        }      

參數中的 newstate就是連接配接的狀态。

連接配接狀态一共分成四種:

一: 已連接配接

二: 正在連接配接

三: 正在斷開

四: 已斷開

不過實際使用中正在連接配接和正在斷開的狀态并沒有真正的傳回給我們的程式,

不過兩個狀态已經夠我們使用了~

連接配接狀态通過連接配接狀态的textview展示一下,我們現在快來看看效果吧~

整體代碼:

MainActivity.class:

package com.wbnq.shouhuan;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button saomiao , duanzhen , changzhen , buting , tingxia;
    private TextView jibu , dianliang , lianjiezhuangtai;
    private ListView list;

    BluetoothAdapter bluetoothAdapter;
    BluetoothGatt bluetoothGatt;
    List<BluetoothDevice> deviceList = new ArrayList<>();
    BluetoothDevice bluetoothDevice;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        //藍牙管理,這是系統服務可以通過getSystemService(BLUETOOTH_SERVICE)的方法擷取執行個體
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        //通過藍牙管理執行個體擷取擴充卡,然後通過掃描方法(scan)擷取裝置(device)
        bluetoothAdapter = bluetoothManager.getAdapter();


    }

    private void initView() {
        saomiao = (Button) findViewById(R.id.saomiao);
        duanzhen = (Button) findViewById(R.id.zhendong);
        changzhen = (Button) findViewById(R.id.changzhen);
        buting = (Button) findViewById(R.id.buting);
        tingxia = (Button) findViewById(R.id.tingxia);
        list = (ListView) findViewById(R.id.list);

        jibu = (TextView) findViewById(R.id.jibu);
        dianliang = (TextView) findViewById(R.id.dianliang);
        lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai);

        saomiao.setOnClickListener(this);
        duanzhen.setOnClickListener(this);
        changzhen.setOnClickListener(this);
        buting.setOnClickListener(this);
        tingxia.setOnClickListener(this);

        //item 監聽事件
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                bluetoothDevice = deviceList.get(i);
                //連接配接裝置的方法,傳回值為bluetoothgatt類型
                bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback);
                lianjiezhuangtai.setText("連接配接" + bluetoothDevice.getName() + "中...");
            }
        });

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.saomiao:
                //開始掃描前開啟藍牙
                Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(turn_on, 0);
                Toast.makeText(MainActivity.this, "藍牙已經開啟", Toast.LENGTH_SHORT).show();

                Thread scanThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i("TAG", "run: saomiao ...");
                        saomiao();
                    }
                });
                scanThread.start();

                break;
            case R.id.zhendong:

                break;
            case R.id.changzhen:

                break;
            case R.id.buting:

                break;
            case R.id.tingxia:

                break;
            case R.id.list:

                break;

        }
    }

    public void saomiao(){
        deviceList.clear();
        bluetoothAdapter.startLeScan(callback);
    }

    //掃描回調
    public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState());

            //重複過濾方法,清單中包含不該裝置才加入清單中,并重新整理清單
            if (!deviceList.contains(bluetoothDevice)) {
                //将裝置加入清單資料中
                deviceList.add(bluetoothDevice);

                list.setAdapter(new MyAdapter(MainActivity.this , deviceList));
            }

        }
    };

    private BluetoothGattCallback gattcallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) {
            super.onConnectionStateChange(gatt, status, newState);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    String status;
                    switch (newState) {
                        //已經連接配接
                        case BluetoothGatt.STATE_CONNECTED:
                            lianjiezhuangtai.setText("已連接配接");

                            //該方法用于擷取裝置的服務,尋找服務
                            bluetoothGatt.discoverServices();
                            break;
                        //正在連接配接
                        case BluetoothGatt.STATE_CONNECTING:
                            lianjiezhuangtai.setText("正在連接配接");
                            break;
                        //連接配接斷開
                        case BluetoothGatt.STATE_DISCONNECTED:
                            lianjiezhuangtai.setText("已斷開");
                            break;
                        //正在斷開
                        case BluetoothGatt.STATE_DISCONNECTING:
                            lianjiezhuangtai.setText("斷開中");
                            break;
                    }
                    //pd.dismiss();
                }
            });
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    } ;
}      

View Code

實作效果:

Android BLE 藍牙程式設計(二)

好啦!!我們功能已經實作了一大部分了呢!!

下節我們就來擷取手環中

我走的步數 , 和電池的電量吧~~

大家加油啦~~~

轉載于:https://www.cnblogs.com/wobeinianqing/p/5879851.html