Android 自定义搜索蓝牙对话框

刚学习了外设连接蓝牙,需要实现一个搜索蓝牙对话框,可以获取已连接的蓝牙和附近发现的蓝牙

        效果如下

                                            

        activity_custom_dialog.xml:主视图布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/search_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="#2196F3"
        android:text="@string/search_bluetooth"/>
    <TextView
        android:id="@+id/mac_address"
        android:layout_width="match_parent"
        android:layout_height="@dimen/item_layout_height"
        android:background="#E6EFEE"
        android:textColor="@color/black"/>

</LinearLayout>

 对话框布局文件:bluetooth_dialog.xml

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/title_layout_height"
        android:background="#3F51B5"
        android:gravity="center"
        android:padding="10dp">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/bluetooth"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_gravity="center_vertical"
                android:src="@drawable/bluetooth_conn" />

            <TextView
                android:id="@+id/tv_bluetooth"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:textColor="@color/white"
                android:textSize="@dimen/title_font_size"
                android:text="@string/bluetoothtitle" />

        </LinearLayout>

        <Button
            android:id="@+id/close_dialog"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_alignParentEnd="true"
            android:background="@drawable/close" />
    </RelativeLayout>
    <ListView
        android:id="@+id/device_list"
        android:layout_width="match_parent"
        android:layout_height="500dp"/>

</LinearLayout>

   list item 布局文件 bluetooth_device_item.xml

<!-- res/layout/item_bluetooth_device.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/title_layout_height"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="24dp"
        android:layout_gravity="center"
        android:layout_height="24dp"
        android:contentDescription="@null"
        android:src="@drawable/baseline_bluetooth_audio_24" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginStart="10dp">

        <TextView
            android:id="@+id/bluetooth_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#1E1D1D"
            android:textSize="@dimen/common_font_size"
            android:text="Bluetooth Device Name" />

        <TextView
            android:id="@+id/mac_address"
            android:layout_width="wrap_content"
            android:layout_marginTop="5dp"
            android:textColor="#6C6B6B"
            android:layout_height="wrap_content"
            android:text="00:11:22:33:AA:BB" />
    </LinearLayout>
    <TextView
        android:id="@+id/isConn_tv"
        android:gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:textColor="#aaaaaa"
        android:textSize="15sp"/>
</LinearLayout>

  主Activity代码

package com.example.drawable;

import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.drawable.utils.BluetoothAlertDialog;

public class BluetoothDialogActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_dialog);
        Button button = findViewById(R.id.search_btn);
        TextView macAddress = findViewById(R.id.mac_address);

        button.setOnClickListener(v -> {
            BluetoothAlertDialog customDialog = new BluetoothAlertDialog(BluetoothDialogActivity.this, new BluetoothAlertDialog.DataBackListener() {
                @Override
                public void getData(String data) {
                    macAddress.setText(data);
                }
            });
            customDialog.show();
        });
    }
}

自定义对话框:BluetoothAlertDialog

package com.example.drawable.utils;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import com.example.drawable.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@SuppressLint("MissingPermission")
public class BluetoothAlertDialog extends Dialog implements AdapterView.OnItemClickListener {

    private final Context context;
    private List<BluetoothDevice> bluetoothDevices;
    private BluetoothDeviceAdapter adapter;
    //创建监听对象
    private final DataBackListener listener;
    //广播开启标志
    private Boolean isReceiverRegistered = false;

    //定义回调接口
    public interface DataBackListener{
        void getData(String data);
    }
    //定义广播接收器
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device != null && !bluetoothDevices.contains(device)) {
                    // 将设备添加到数据源中
                    bluetoothDevices.add(device);
                    //通知适配器更新列表
                    adapter.notifyDataSetChanged();
                }
            }
        }
    };

    public BluetoothAlertDialog(Context context, final DataBackListener listener) {
        super(context);
        this.context = context;
        this.listener = listener;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.bluetooth_dialog, null);
        setContentView(view);
        ListView listView = findViewById(R.id.device_list);
        //获取默认蓝牙适配器
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter==null){
            Toast.makeText(context, R.string.unsupported_bluetooth, Toast.LENGTH_SHORT).show();
        }else {
            //判断适配器是否可用,如果可用
            if (bluetoothAdapter.isEnabled()) {
                searchBluetooth(bluetoothAdapter, listView);
            }else {
                Toast.makeText(context, R.string.request_open_bluetooth, Toast.LENGTH_SHORT).show();
            }
        }

        //给list设置item点击监听事件
        listView.setOnItemClickListener(this);
        Button closeBtn = findViewById(R.id.close_dialog);
        closeBtn.setOnClickListener(v -> dismiss());
    }
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        BluetoothDevice selectedDevice = bluetoothDevices.get(position);
        if(selectedDevice!=null){
            String address = selectedDevice.getAddress();
            listener.getData(address);
            dismiss();
        }
    }

    /**
     * 搜索蓝牙
     * @param bluetoothAdapter 蓝牙列表适配器
     * @param listView 蓝牙列表
     */
    private void searchBluetooth(BluetoothAdapter bluetoothAdapter, ListView listView) {
        //获取已配对的蓝牙
        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        bluetoothDevices = new ArrayList<>(pairedDevices);
        //创建自定义视图适配器
        adapter = new BluetoothDeviceAdapter(getContext(), bluetoothDevices);
        //给list组件设置适配器
        listView.setAdapter(adapter);
        //创建蓝牙广播意图对象
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        //注册广播接收器,传一个广播对象,一个意图对象
        context.registerReceiver(mReceiver, filter);
        isReceiverRegistered = true;
        //开启搜索广播
        bluetoothAdapter.startDiscovery();
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (isReceiverRegistered) { // 添加一个标志位来检查是否已注册
            try {
                context.unregisterReceiver(mReceiver);
                isReceiverRegistered = false;
            } catch (IllegalArgumentException e) {
                Log.e("BluetoothAlertDialog", "An error occurred", e);
            }
        }
    }
}

列表适配器:BluetoothDeviceAdapter

package com.example.drawable.utils;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.drawable.R;

import java.util.List;

@SuppressLint("MissingPermission")
public class BluetoothDeviceAdapter extends ArrayAdapter<BluetoothDevice> {
    private final Context context;

    public BluetoothDeviceAdapter(Context context, List<BluetoothDevice> devices) {
        super(context, 0, devices);
        this.context = context;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.bluetooth_device_item, parent, false);
        }

        ImageView icon = convertView.findViewById(R.id.icon);
        TextView bluetoothName = convertView.findViewById(R.id.bluetooth_name);
        TextView macAddress = convertView.findViewById(R.id.mac_address);
        TextView isConn = convertView.findViewById(R.id.isConn_tv);
        BluetoothDevice device = getItem(position);

        if (device != null) {
            bluetoothName.setText(device.getName());
            macAddress.setText(device.getAddress());
            int bondState = device.getBondState();
            if (BluetoothDevice.BOND_BONDED == bondState) {
                isConn.setText("已配对");
            }

            BluetoothClass bluetoothClass = device.getBluetoothClass();
            if (bluetoothClass != null) {
                int deviceClass = bluetoothClass.getDeviceClass();
                switch (deviceClass) {
                    case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
                        icon.setImageResource(R.drawable.wearable);
                        break;
                    case BluetoothClass.Device.COMPUTER_DESKTOP:
                    case BluetoothClass.Device.COMPUTER_LAPTOP:
                        icon.setImageResource(R.drawable.pc);
                        break;
                    case BluetoothClass.Device.PHONE_SMART:
                    case BluetoothClass.Device.PHONE_CELLULAR:
                        icon.setImageResource(R.drawable.phone);
                        break;
                    default:
                        icon.setImageResource(R.drawable.bluetooth);
                        break;
                }
            } else {
                icon.setImageResource(R.drawable.bluetooth);
            }
        }
        return convertView;
    }
}

需要开启的权限,有时可能或需要手动申请权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

 字符串可以自己添加,下面是图标资源

 bluetooth.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#231815" android:pathData="M756.7,679.8l0.1,-0.1L561.2,512l195.6,-167.7 -0.1,-0.1c6.8,-5.9 11.3,-14.5 11.3,-24.2a31.8,31.8 0,0 0,-11.3 -24.2l0.1,-0.1 -224,-192 -0.1,0.1C527.1,99 520,96 512,96a32,32 0,0 0,-32 32v314.4l-171.2,-146.7 -0.1,0.1c-5.6,-4.8 -12.8,-7.8 -20.7,-7.8a32,32 0,0 0,-32 32c0,9.7 4.4,18.3 11.3,24.2l-0.1,0.1L462.8,512 267.2,679.7l0.1,0.1A31.8,31.8 0,0 0,256 704a32,32 0,0 0,32 32c8,0 15.1,-3 20.7,-7.8l0.1,0.1L480,581.6V896a32,32 0,0 0,32 32c8,0 15.1,-3 20.7,-7.8l0.1,0.1 224,-192 -0.1,-0.1A31.8,31.8 0,0 0,768 704a31.8,31.8 0,0 0,-11.3 -24.2zM686.8,704L544,826.4V581.6L686.8,704zM544,442.4V197.6L686.8,320 544,442.4z"/>
    
</vector>

 bluetooth_conn.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#FFFFFF" android:pathData="M397.1,493.7l215.2,-229.7a35.4,35.4 0,0 0,-3 -51.3L365.8,8.5A35.4,35.4 0,0 0,307.4 35.5L307.4,405L115.9,214.8a35.4,35.4 0,0 0,-49.8 50.2l232.3,230.3L65.3,744.1a35.4,35.4 0,0 0,51.6 48.5l190.7,-203.3v399.3a35.4,35.4 0,0 0,61 24.3l243.5,-256.7a35.4,35.4 0,0 0,-0.8 -49.2l-214.4,-213.3zM378.5,111.5L535.2,243.1 378.5,410.5zM378.5,899.2L378.5,574.6l158.6,157.4zM718.3,307.3a35.4,35.4 0,1 0,-58.8 39.4,228.3 228.3,0 0,1 0,253 35.4,35.4 0,0 0,58.7 39.4,298.7 298.7,0 0,0 0,-331.8zM930.2,290.1a482.3,482.3 0,0 0,-45.5 -85.2,35.4 35.4,0 1,0 -58.8,39.3 421.9,421.9 0,0 1,0 468.3,35.4 35.4,0 0,0 58.8,39.4A492.3,492.3 0,0 0,930.2 290.1z"/>
    
</vector>

bluetooth_title_logo.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
      
    <path android:fillColor="@android:color/white" android:pathData="M14.24,12.01l2.32,2.32c0.28,-0.72 0.44,-1.51 0.44,-2.33 0,-0.82 -0.16,-1.59 -0.43,-2.31l-2.33,2.32zM19.53,6.71l-1.26,1.26c0.63,1.21 0.98,2.57 0.98,4.02s-0.36,2.82 -0.98,4.02l1.2,1.2c0.97,-1.54 1.54,-3.36 1.54,-5.31 -0.01,-1.89 -0.55,-3.67 -1.48,-5.19zM15.71,7.71L10,2L9,2v7.59L4.41,5 3,6.41 8.59,12 3,17.59 4.41,19 9,14.41L9,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM11,5.83l1.88,1.88L11,9.59L11,5.83zM12.88,16.29L11,18.17v-3.76l1.88,1.88z"/>
    
</vector>

close.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#C9D1E1" android:pathData="M512,0c282.5,0 512,229.5 512,512s-229.5,512 -512,512S0,794.5 0,512 229.5,0 512,0zM667.1,304.7L512,459.9l-155.1,-155.1 -51.7,51.7 155.1,155.2 -155.1,155.1 51.7,51.7 155.1,-155.1 155.1,155.1 51.7,-51.7 -155.1,-155.1 155.1,-155.1 -51.7,-51.7z"/>
    
</vector>

pc.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#FF000000" android:pathData="M900.1,904.6"/>
      
    <path android:fillColor="#FF000000" android:pathData="M948.1,811.2l-45.1,0L121,811.2 75.9,811.2c-24.9,0 -45.1,-20.1 -45.1,-44.9l0,-74.8 90.2,0L121,257.7c0,-24.8 20.2,-44.9 45.1,-44.9l691.7,0c24.9,0 45.1,20.1 45.1,44.9l0,433.9 90.2,0 0,74.8C993.2,791.2 973,811.2 948.1,811.2zM406.7,766.4l210.5,0 0,-29.9L406.7,736.4 406.7,766.4zM842.8,272.6 L181.2,272.6l0,389 661.6,0L842.8,272.6z"/>
    
</vector>

phone.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#FF000000" android:pathData="M776.7,1010.1h-479.9c-28.3,0 -51.3,-23 -51.3,-51.3v-891.1c0,-28.3 23,-51.3 51.3,-51.3h479.9c28.3,0 51.3,23 51.3,51.3v891.1c0,28.3 -23,51.3 -51.3,51.3v0zM536.6,958.8c19.1,0 34.2,-15.4 34.2,-34.2s-15.4,-34.2 -34.2,-34.2 -34.2,15.4 -34.2,34.2 15.4,34.2 34.2,34.2v0zM776.7,119h-479.9v719.7h479.6v-719.7h0.3z"/>
    
</vector>

wearable.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="1024" android:viewportWidth="1024" android:width="24dp">
      
    <path android:fillColor="#44454A" android:pathData="M866.5,445.1L866.5,402.9c0,-190.9 -155.3,-346.2 -346.2,-346.2S174.1,212 174.1,402.9v38.6c-50.5,11.7 -88.2,56.9 -88.2,110.9v94.5c0,62.8 51,113.8 113.8,113.8s113.8,-51 113.8,-113.8v-94.5c0,-54 -37.7,-99.2 -88.2,-110.9v-38.6c0,-162.7 132.4,-295 295,-295 162.7,0 295,132.4 295,295v36.4c-56.6,6.5 -100.8,54.7 -100.8,113v94.5c0,53.6 37.2,98.6 87.2,110.6 -4.7,28 -28.2,90.6 -143.9,112.1 -13.9,2.6 -23.1,15.9 -20.5,29.8a25.6,25.6 0,0 0,25.1 20.9c1.5,0 3.1,-0.2 4.7,-0.4 152.9,-28.4 180.8,-122.4 185.8,-162 51,-11.3 89.2,-56.8 89.2,-111.2v-94.5c-0.1,-49.4 -31.7,-91.5 -75.7,-107.2zM262.3,552.3v94.5c0,34.6 -28.1,62.6 -62.6,62.6 -34.6,0 -62.6,-28.1 -62.6,-62.6v-94.5c0,-34.6 28.1,-62.6 62.6,-62.6s62.6,28.1 62.6,62.6zM891,646.9c0,34.6 -28.1,62.6 -62.6,62.6s-62.6,-28.1 -62.6,-62.6v-94.5c0,-34.6 28.1,-62.6 62.6,-62.6s62.6,28.1 62.6,62.6v94.5z"/>
      
    <path android:fillColor="#44454A" android:pathData="M531.4,902.7m-61.4,0a61.4,61.4 0,1 0,122.9 0,61.4 61.4,0 1,0 -122.9,0Z"/>
    
</vector>

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

꧁꫞南鸢꫞꧂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值