Bootstrap

Android Studio开发学习(八、蓝牙设备连接)

引言

        上篇我们介绍了整体蓝牙模块的基本写法Android Studio开发学习(七、蓝牙模块java)-CSDN博客,当然我们检测到蓝牙设备肯定会连接蓝牙,那么如何实现蓝牙连接呢,这篇博客将实现这个功能。

 设备连接

        connectDevice 方法用于在后台线程中尝试连接到指定的蓝牙设备,并在连接成功或失败时显示相应的提示信息。成功时显示“连接成功”的提示并跳转到新 Activity,失败时显示“连接失败”的提示,使用唯一的UUID标识蓝牙服务,并确保UI更新在主线程中完成。

连接成功:

连接失败:

弹窗提示

        我们在上篇博客基础上增加部分代码,使用 AlertDialog 来显示连接状态。先来介绍一下AlertDialog :

        AlertDialog 是 Android 中用于显示警告信息、提示用户操作或要求用户确认操作的对话框组件。它可以显示标题、消息、按钮,甚至是自定义视图。AlertDialog 是通过 AlertDialog.Builder 类来构建和显示的。下面是一个显示简单的消息对话框例子:

new AlertDialog.Builder(context)
    .setTitle("标题")
    .setMessage("消息对话框")
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            // 用户点击确定按钮后的操作
        }
    })
    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            // 用户点击取消按钮后的操作
        }
    })
    .show();

 蓝牙模块中的 AlertDialog 应用:

实机演示

完整代码

BlueToothActivity.java

package com.example.login.BlueTooth;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.example.login.R;

import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;

public class BlueToothActivity extends AppCompatActivity {
    // 实例化蓝牙控制器
    public BlueToothController btController = new BlueToothController();
    // 蓝牙权限列表
    public ArrayList<String> requestList = new ArrayList<>();
    // 弹窗
    private Toast mToast;
    public ArrayAdapter adapter1;
    // 定义一个列表,存蓝牙设备地址,用于显示。
    public ArrayList<String> device = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bluetooth);
        // 获取ListView组件
        ListView listView = findViewById(R.id.listView1);
        // 实例化ArrayAdapter对象
        adapter1 = new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1, device);
        // 添加到ListView组件中
        listView.setAdapter(adapter1);
        // ListView的列表点击事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @SuppressLint("MissingPermission")
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                CharSequence content = ((TextView) view).getText();
                // 获取蓝牙的名称和地址
                String con = content.toString();
                // 换行为切割
                String[] conArray = con.split("\n");
                // 获取蓝牙地址
                String rightStr = conArray[1].substring(5);
                BluetoothDevice device1 = btController.find_device(rightStr);
                connectDevice(device1);
            }
        });

        Button open_Bt = findViewById(R.id.openBT);
        open_Bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                turnOnBt();
            }
        });

        Button close_Bt = findViewById(R.id.closeBT);
        close_Bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getPermision();
                // 关闭蓝牙
                btController.turnOffBlueTooth();
            }
        });

        Button state_Bt = findViewById(R.id.stateBT);
        state_Bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getPermision();
                // 判断当前蓝牙状态
                boolean ret = btController.getBlueToothStatus();
                // 弹窗显示结果
                showToast("当前蓝牙状态:" + ret);
            }
        });

        Button update_list = findViewById(R.id.updateList);
        update_list.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("MissingPermission")
            @Override
            public void onClick(View view) {
                getPermision();
                // 初始化列表
                device.clear();
                adapter1.notifyDataSetChanged();
                // 获取已绑定蓝牙列表
                ArrayList<BluetoothDevice> bluetoothDevices = btController.getBondedDeviceList();
                // 更新列表
                for (BluetoothDevice device1 : bluetoothDevices) {
                    if (device1.getBondState() == BluetoothDevice.BOND_BONDED) {
                        device.add("设备名:" + device1.getName() + "\n" + "设备地址:" + device1.getAddress());
                    } else {
                        device.add("设备名:" + device1.getName() + "\n" + "设备地址:" + device1.getAddress() + "\n" + "连接状态:未知");
                    }
                    adapter1.notifyDataSetChanged();
                }
            }
        });
    }

    @SuppressLint("MissingPermission")
    private void connectDevice(final BluetoothDevice device) {
        final UUID MY_UUID = UUID.randomUUID();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BluetoothSocket socket = device.createRfcommSocketToServiceRecord(MY_UUID);
                    socket.connect();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            showAlert("连接成功", "设备名:" + device.getName() + "\n设备地址:" + device.getAddress());
                            // 跳转到新Activity
                            Intent intent = new Intent(BlueToothActivity.this, DataActivity.class);
                            Bundle bundle = new Bundle();
                            bundle.putString("deviceAddr", device.getAddress());
                            intent.putExtras(bundle);
                            startActivity(intent);
                            finish();
                        }
                    });
                } catch (IOException e) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            showAlert("连接失败", "设备名:" + device.getName() + "\n设备地址:" + device.getAddress());
                        }
                    });
                }
            }
        }).start();
    }

    private void showAlert(String title, String message) {
        new AlertDialog.Builder(this)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("确定", null)
                .show();
    }

    public static class BlueToothController {
        private BluetoothAdapter BtAdapter;
        
        public BlueToothController() {
            // 获取本地的蓝牙适配器
            BtAdapter = BluetoothAdapter.getDefaultAdapter();
        }

        @SuppressLint("MissingPermission")
        // 打开蓝牙
        public void turnOnBlueTooth(Activity activity, int requestCode) {
            if (!BtAdapter.isEnabled()) {
                Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                activity.startActivityForResult(intent, requestCode);
            }
        }

        @SuppressLint("MissingPermission")
        // 关闭蓝牙
        public void turnOffBlueTooth() {
            if (BtAdapter.isEnabled()) {
                BtAdapter.disable();
            }
        }

        // 获取蓝牙状态
        public boolean getBlueToothStatus() {
            // 断言,避免BtAdapter为null导致return出错
            assert (BtAdapter != null);
            // 蓝牙状态
            return BtAdapter.isEnabled();
        }

        @SuppressLint("MissingPermission")
        // 获取设备信息
        public ArrayList<BluetoothDevice> getBondedDeviceList() {
            return new ArrayList<>(BtAdapter.getBondedDevices());
        }

        // 根据蓝牙地址找到相应的设备
        public BluetoothDevice find_device(String addr) {
            return BtAdapter.getRemoteDevice(addr);
        }
    }

    public void turnOnBt() {
        getPermision();
        // 打开蓝牙
        btController.turnOnBlueTooth(this, 1);
    }

  
    public void getPermision() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            requestList.add(Manifest.permission.BLUETOOTH_SCAN);
            requestList.add(Manifest.permission.BLUETOOTH_ADVERTISE);
            requestList.add(Manifest.permission.BLUETOOTH_CONNECT);
            requestList.add(Manifest.permission.ACCESS_FINE_LOCATION);
            requestList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
            requestList.add(Manifest.permission.BLUETOOTH);
        }
        if (requestList.size() != 0) {
            ActivityCompat.requestPermissions(this, requestList.toArray(new String[0]), 1);
        }
    }

    public void showToast(String text) {
        // 若Toast控件未初始化
        if (mToast == null) {
            // 则初始化
            mToast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
        } else {
            // 修改显示文本
            mToast.setText(text);
        }
        // 显示
        mToast.show();
    }
}

activity_bluetooth.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background1"
    tools:context=".BlueTooth.BlueToothActivity">


    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="136dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toTopOf="@+id/listView1"
        app:layout_constraintGuide_end="206dp"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/openBT"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="打开蓝牙"
        app:layout_constraintBottom_toTopOf="@+id/stateBT"
        app:layout_constraintEnd_toStartOf="@id/guideline1"
        app:layout_constraintHorizontal_bias="0.567"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/closeBT"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="关闭蓝牙"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.473"
        app:layout_constraintStart_toEndOf="@id/guideline1"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/stateBT"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="蓝牙状态"
        app:layout_constraintEnd_toStartOf="@id/guideline1"
        app:layout_constraintHorizontal_bias="0.567"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/openBT" />

    <Button
        android:id="@+id/updateList"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="更新列表"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.473"
        app:layout_constraintStart_toEndOf="@id/guideline1"
        app:layout_constraintTop_toBottomOf="@id/closeBT" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="307dp"
        android:layout_height="46dp"
        android:layout_marginTop="92dp"
        android:background="#2196F3"
        android:gravity="center"
        android:text="蓝牙列表"
        android:textSize="24dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.495"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/stateBT" />
    <ListView
        android:id="@+id/listView1"
        android:layout_width="332dp"
        android:layout_height="350dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.491"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView1"
        app:layout_constraintVertical_bias="0.316" />

</androidx.constraintlayout.widget.ConstraintLayout>
;