2021-05-22

安卓蓝牙开发,实现了两个功能点:(1)开启蓝牙(2)扫描蓝牙

开启蓝牙使用BlueAdapter.enable就可以开启,但扫描蓝牙的前提是要发现蓝牙,所以写一个接口,蓝牙监听接口。

蓝牙监听接口:

package com.lyc.myfiresttooth.callback;
import android.bluetooth.BluetoothDevice;
public interface BleListen {
    /** 发现蓝牙设备 */
    void foundDevice(BluetoothDevice device);
}

该项目界面非常简单,上代码和截图

activity_main.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"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/empty"
        android:visibility="visible"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bluetooth free connection"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:orientation="vertical"/>
</androidx.constraintlayout.widget.ConstraintLayout>

这是activity_main.xml的界面

搜索蓝牙按钮在状态栏中定义:如下

main.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:visible="true"
        android:id="@+id/action_search"
        android:title="搜索"
        android:orderInCategory="100"
        app:showAsAction="always" />
    <item
        android:visible="false"
        android:id="@+id/action_stop"
        android:title="停止"
        android:orderInCategory="100"
        app:showAsAction="always" />
</menu>

这是main.xml的界面 

写主代码之前,最好先配置一下权限,减少不必要的·麻烦,在AndroidManifest.xml中写入以下代码:

<uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

MainActivity.java实现 interface BleListen接口:

在主函数中实现其接口的方法:

@Override
    public void foundDevice(BluetoothDevice device) {
    mBleList.add(device);
    mBleAdapter.notifyDataSetChanged();
}

初始化状态栏:

@Override
    public Boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater=getMenuInflater();
    inflater.inflate(R.menu.main,menu);
    return true;
}
//isFlag根据该值的真假来判断显示搜索按钮还是停止搜索按钮
Boolean isFlag=true;
//搜索菜单按钮
MenuItem search;
//停止菜单按钮
MenuItem stop;
@Override
    public Boolean onPrepareOptionsMenu(Menu menu) {
    search=menu.findItem(R.id.action_search);
    stop=menu.findItem(R.id.action_stop);
    if(isFlag){
        search.setVisible(true);
        stop.setVisible(false);
    } else{
        search.setVisible(false);
        stop.setVisible(true);
    }
    return super.onPrepareOptionsMenu(menu);
}
@Override
    public Boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()){
        case R.id.action_search:
        mArrayList.clear();
        permissionsOk();
        isFlag=false;
        break;
        case R.id.action_stop:
        break;
    }
    return super.onOptionsItemSelected(item);
}

搜索中的permissionsOk();是今天的主角色,权限的获取与蓝牙开启和蓝牙扫描都在这里实现。

private void permissionsOk() {
    if(Build.VERSION.SDK_iNT>=Build.VERSION_CODES.M){
        int i= ContextCompat.checkSelfPermission(getApplicationContext(),permissions[0]);
        if(i!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,permissions,mRequestCode);
        } else {
            scanDevice();
        }
    }
}

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode==mRequestCode){
        Boolean isAllGranted=true;
        for (int result:grantResults){
            if(result==PackageManager.PERMISSION_DENIED){
                isAllGranted=false;
                break;
            }
        }
        if(isAllGranted){
            scanDevice();
        } else{
        }
    }
}

助解:当权限获取失败,则相应请求码进行·获取权限。获取成功则进行扫描蓝牙。

private void scanDevice() {
    mBleList.clear();
    getPopwindow();
    popupWindow.showAtLocation(getLayoutInflater().inflate(R.layout.pop_bottom,null,false), Gravity.CENTER,0,0);
    if(isAdapterEnable()){
        mBluetoothAdapter.startLeScan(scanCallback);
    } else{
        mBluetoothAdapter.enable();
    }
}

getPopwindow();的实现:

private void getPopwindow() {
    if(null!=popupWindow){
        popupWindow.dismiss();
    } else{
        initPopupWindow();
    }
}

 initPopupWindow();的实现

private void initPopupWindow() {
    View popupWindowView = getLayoutInflater().inflate(R.layout.pop_bottom, null, false);
    RecyclerView mRecylerView =  popupWindowView.findViewById(R.id.recycler_view);
    mRecylerView.setAdapter(mBleAdapter);
    popupWindow=new PopupWindow(popupWindowView,2*width/3,2*height/3,true);
    popupWindow.setAnimationStyle(R.style.AnimationUpDown);
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);
}

isAdapterEnable()方法的实现:

private Boolean isAdapterEnable(){
    return BluetoothAdapter.getDefaultAdapter().isEnabled();
}

mBluetoothAdapter = initBluetoothAdapter();的实现:

/**
     * 获取蓝牙适配器
     */
private BluetoothAdapter initBluetoothAdapter() {
    BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    return mBluetoothManager.getAdapter();
}

initPopupWindow()中  mRecylerView.setAdapter(mBleAdapter);的实现:
private BleAdapter mBleAdapter;
mBleAdapter=new BleAdapter();
public class BleAdapter extends RecyclerView.Adapter<BleHolder>{
    @NonNull
            @Override
            public BleHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view=getLayoutInflater().inflate(R.layout.ble_item,parent,false);
        return new BleHolder(view);
    }
    @Override
            public void onBindViewHolder(@NonNull BleHolder holder, int position) {
        BluetoothDevice device=mBleList.get(position);
        holder.device=device;
        String name=device.getName()==null ? "unknown" : device.getName();
        holder.text1.setText(name);
        SpannableStringBuilder info=new SpannableStringBuilder();
        info.append("Mac:").append(device.getAddress());
        info.setSpan(new ForegroundColorSpan(0xFF9E9E9E), 0, 21, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        info.setSpan(new ForegroundColorSpan(0xFF8D6E63), 21, info.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        holder.text2.setText(info);
    }
    @Override
            public int getItemCount() {
        return mBleList.size();
    }
}
RecyclerView.Adapter<BleHolder>中BleHolder的实现:

private class BleHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    BluetoothDevice device;
    TextView text1;
    TextView text2;
    BleHolder(View itemView) {
        super(itemView);
        text1 = itemView.findViewById(android.R.id.text1);
        text2 = itemView.findViewById(android.R.id.text2);
        text2.setTextSize(14);
        itemView.setOnClickListener(this);
    }
    @Override
            public void onClick(View v) {
        ThisApplication.getApplication().setBluetoothDevice(device, MainActivity.this);
        popupWindow.dismiss();
        dialog = WeiboDialogUtils.createLoadingDialog(MainActivity.this, "正在连接");
    }
}

dialog的实现:

package com.lyc.myfiresttooth.util;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.lyc.myfiresttooth.R;
public class WeiboDialogUtils {
    public static Dialog createLoadingDialog(Context context, String msg) {
        LayoutInflater inflater = LayoutInflater.from(context);
        // 得到加载view
        View v = inflater.inflate(R.layout.dialog_loading, null);
        // 加载布局
        LinearLayout layout = (LinearLayout) v
                        .findViewById(R.id.dialog_loading_view);
        // 提示文字
        TextView tipTextView = (TextView) v.findViewById(R.id.tipTextView);
        // 设置加载信息
        tipTextView.setText(msg);
        // 创建自定义样式dialog
        Dialog loadingDialog = new Dialog(context, R.style.MyDialogStyle);
        // 是否可以按“返回键”消失
        loadingDialog.setCancelable(true);
        // 点击加载框以外的区域
        loadingDialog.setCanceledOnTouchOutside(false);
        loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT,
                        // 设置布局
        LinearLayout.LayoutParams.MATCH_PARENT));
        /**
         *将显示Dialog的方法封装在这里面
         */
        Window window = loadingDialog.getWindow();
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        window.setGravity(Gravity.CENTER);
        window.setAttributes(lp);
        window.setWindowAnimations(R.style.PopWindowAnimStyle);
        loadingDialog.show();
        return loadingDialog;
    }
    /**
     * 关闭dialog
     * @param mDialogUtils
     */
    public static void closeDialog(Dialog mDialogUtils) {
        if (mDialogUtils != null && mDialogUtils.isShowing()) {
            mDialogUtils.dismiss();
        }
    }
}

mBluetoothAdapter.startLeScan(scanCallback);中scanCallback的实现:

主函数中实例化:

private ScanCallback scanCallback;
scanCallback=new ScanCallback(mBluetoothAdapter,this);

ScanCallback类:

package com.lyc.myfiresttooth.callback;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import java.util.ArrayList;
public class ScanCallback implements BluetoothAdapter.LeScanCallback {
    public static ArrayList<String> mArrayList = new ArrayList<>();
    private BluetoothAdapter mBluetoothAdapter;
    private BleListen mBleListen;
    public ScanCallback(BluetoothAdapter bluetoothAdapter, BleListen bleListen){
        mBluetoothAdapter = bluetoothAdapter;
        mBleListen = bleListen;
    }
    @Override
        public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
        String blueName = "YHD-MODULE";
        if (bluetoothDevice.getName() != null && bluetoothDevice.getName().equals(blueName) && !mArrayList.contains(bluetoothDevice.getAddress())){
            mArrayList.add(bluetoothDevice.getAddress());
            mBleListen.foundDevice(bluetoothDevice);
        }
    }
}

ThisApplication类:

package com.lyc.myfiresttooth.activity;
import android.app.Application;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.content.SharedPreferences;
import android.os.Build;
import com.lyc.myfiresttooth.callback.BTGattCallback;
import com.lyc.myfiresttooth.callback.BleListen;
import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
public class ThisApplication extends Application {
    private static ThisApplication application;
    private SharedPreferences sharedPreferences;
    private BluetoothGatt mBluetoothGatt;
    @Override
        public void onCreate() {
        super.onCreate();
        application=this;
        sharedPreferences=getApplicationContext().getSharedPreferences("Write",MODE_PRIVATE);
    }
    public static synchronized ThisApplication getApplication(){
        return application;
    }
    public BluetoothGatt getBluetoothGatt(){
        return mBluetoothGatt;
    }
    public void setBluetoothGatt(BluetoothGatt bluetoothGatt){
        this.mBluetoothGatt=bluetoothGatt;
    }
    public void setBluetoothDevice(BluetoothDevice bluetoothDevice, BleListen bleListen){
        if(Build.VERSION.SDK_iNT>=Build.VERSION_CODES.Q){
            mBluetoothGatt=bluetoothDevice.connectGatt(getApplicationContext(),true, BTGattCallback.getInstance(bleListen),TRANSPORT_LE);
        } else {
            mBluetoothGatt=bluetoothDevice.connectGatt(getApplicationContext(),true,BTGattCallback.getInstance(bleListen));
        }
        setBluetoothGatt(mBluetoothGatt);
    }
}

结束。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值