安卓蓝牙开发,实现了两个功能点:(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);
}
}
结束。