当前位置:   article > 正文

【AndroidStudio开发】(三)经典蓝牙+BLE蓝牙搜索_android开发实现bt配对搜索连接其他bt功能

android开发实现bt配对搜索连接其他bt功能

系列文章目录

【AndroidStudio开发】(一):新建页面切换项目

【AndroidStudio开发】(二):加入摇杆控制

【AndroidStudio开发】(三):经典蓝牙+BLE蓝牙搜索

【AndroidStudio开发】(四):蓝牙BLE设备连接


目录

系列文章目录

一、蓝牙的区别?

二、具体实现

1.查看系统app目录下的build.gradle配置

2.获取系统权限

(1)AndroidManifest.xml文件

(2)创建一个文本弹出框的类APP

(3)MainActivity文件

(4)增加一个蓝牙设备列表数据结构

(5)增加一个广播接收类BtReceiver

(6)FirstFragment文件

3.页面设计

(1) fragment_first.xml 文件

(2) 增加activity_listview.xml 文件

(3)activity_main.xml文件

(4)其它文件

4.连接设备调试

(1)连接手机

(2)打开MainActivity文件

(3)实际效果


前言

        上一次我们改造的是第二个页面,在页面中加入摇杆按钮,虽然我们可以拖动界面的按钮到任何一个方向,但是还是处于模拟器的操纵,没有用手机进行真机调试。现在我们需要对第一个页面进行改造,加入我们的蓝牙搜索及连接,这样我们就可以通过蓝牙连接设备,然后通过摇杆遥控,实际控制现实世界的物品。


一、蓝牙的区别?

        蓝牙其实分经典蓝牙和BLE两种,比如我们常见的HC-05、HC-06蓝牙模块都属于经典蓝牙,ESP32自带的蓝牙是属于BLE这种的,BLE是蓝牙协议4.0之后开始升级的,叫做低功耗蓝牙,这两种蓝牙使用过程中是存在区别的。

        第一个,BLE在安卓6.0之后,不仅需要动态获取系统蓝牙权限,还需要获取系统定位权限。

        第二个,蓝牙的搜索模式差不多,但是连接操作和写入操作完全不一样了。搜索的话,都是先通过注册一个蓝牙广播BtReceiver,再通过startDiscovery进行搜索,添加设备都是通过跟系统建立intent来获取搜索到的设备。但在连接和写入方面,经典蓝牙是通过创建一个Scoket,再通过其输入流getInputStream、输出流getOutputStream完成。BLE是通过BluetoothGatt的connectGatt、disconnect完成连接和断连,而发送消息必须要通过UUID获取BluetoothGatt的服务再进行写入。

二、具体实现

1.查看系统app目录下的build.gradle配置

因为创建项目选的是API 28,所以需要修改下面红色的配置。大部分点击搜索按钮后,没有显示任何蓝牙设备的时候,可以看看这个地方配置是否跟API版本一致,手机安卓系统是否支持该版本。

compileSdkVersion 28
buildToolsVersion '28.0.3'

defaultConfig {
    applicationId "com.example.myapplication"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

2.获取系统权限

(1)AndroidManifest.xml文件

  1. <uses-permission android:name="android.permission.BLUETOOTH" />
  2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  3. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  4. <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

完整的AndroidManifest.xml文件,并增加一个后面的文本框类的关联,android:name=".APP"

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.myapplication">
  4. <uses-permission android:name="android.permission.BLUETOOTH" />
  5. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  6. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  7. <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
  8. <application
  9. android:name=".APP"
  10. android:allowBackup="true"
  11. android:icon="@mipmap/ic_launcher"
  12. android:label="@string/app_name"
  13. android:roundIcon="@mipmap/ic_launcher_round"
  14. android:supportsRtl="true"
  15. android:theme="@style/Theme.MyApplication">
  16. <activity
  17. android:name=".MainActivity"
  18. android:label="@string/app_name"
  19. android:theme="@style/Theme.MyApplication.NoActionBar">
  20. <intent-filter>
  21. <action android:name="android.intent.action.MAIN" />
  22. <category android:name="android.intent.category.LAUNCHER" />
  23. </intent-filter>
  24. </activity>
  25. </application>
  26. </manifest>

(2)创建一个文本弹出框的类APP

  1. package com.example.myapplication;
  2. import android.annotation.SuppressLint;
  3. import android.app.Application;
  4. import android.os.Handler;
  5. import android.widget.Toast;
  6. public class APP extends Application {
  7. private static final Handler sHandler = new Handler();
  8. private static Toast sToast; // 单例Toast,避免重复创建,显示时间过长
  9. @SuppressLint("ShowToast")
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. sToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
  14. }
  15. public static void toast(String txt, int duration) {
  16. sToast.setText(txt);
  17. sToast.setDuration(duration);
  18. sToast.show();
  19. }
  20. public static void runUi(Runnable runnable) {
  21. sHandler.post(runnable);
  22. }
  23. }

(3)MainActivity文件

        增加静态常量,删除fab按钮,增加蓝牙硬件的检查,蓝牙是否开启,动态获取定位授权。

  1. private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. // 检查蓝牙开关
  7. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  8. if (adapter == null) {
  9. APP.toast("本机没有找到蓝牙硬件或驱动!", 0);
  10. finish();
  11. return;
  12. } else {
  13. if (!adapter.isEnabled()) {
  14. //直接开启蓝牙
  15. adapter.enable();
  16. //跳转到设置界面
  17. //startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 112);
  18. }
  19. }
  20. //检查是否支持BLE
  21. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
  22. APP.toast("系统不支持BLE", Toast.LENGTH_SHORT);
  23. finish();
  24. }
  25. // Make sure we have access coarse location enabled, if not, prompt the user to enable it
  26. if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
  27. final android.app.AlertDialog.Builder builder = new AlertDialog.Builder(this);
  28. builder.setTitle("定位授权");
  29. builder.setMessage("请授予位置访问权限,以便此应用可以检测外围设备");
  30. builder.setPositiveButton(android.R.string.ok, null);
  31. builder.setOnDismissListener(dialog -> requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION));
  32. builder.show();
  33. }
  34. Toolbar toolbar = findViewById(R.id.toolbar);
  35. setSupportActionBar(toolbar);
  36. }

(4)增加一个蓝牙设备列表数据结构LeDeviceListAdapter

  1. package com.example.myapplication;
  2. import android.bluetooth.BluetoothAdapter;
  3. import android.bluetooth.BluetoothDevice;
  4. import android.content.Context;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.BaseAdapter;
  9. import android.widget.TextView;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. import java.util.Set;
  13. /**
  14. * Created by xanadw on 10/24/2021.
  15. */
  16. public class LeDeviceListAdapter extends BaseAdapter {
  17. private ArrayList<BluetoothDevice> deviceArrayList;
  18. private Context context;
  19. private LayoutInflater mInflater;
  20. private List<Integer> mRssis;
  21. private List<String> mBletype;
  22. public LeDeviceListAdapter(Context context, ArrayList<BluetoothDevice> devices, List<Integer> rssis, List<String> bletype) {
  23. this.context = context;
  24. this.deviceArrayList = devices;
  25. mInflater = LayoutInflater.from(this.context);
  26. mRssis = rssis;
  27. mBletype = bletype;
  28. }
  29. @Override
  30. public int getCount() {
  31. return deviceArrayList.size();
  32. }
  33. @Override
  34. public BluetoothDevice getItem(int position){
  35. return deviceArrayList.get(position);
  36. }
  37. @Override
  38. public long getItemId(int position) {
  39. return position;
  40. }
  41. @Override
  42. public View getView(int position, View convertView, ViewGroup parent) {
  43. MyViewHolder mViewHolder;
  44. if (convertView == null) {
  45. convertView = mInflater.inflate(R.layout.activity_listview, parent, false);
  46. mViewHolder = new MyViewHolder(convertView);
  47. convertView.setTag(mViewHolder);
  48. }else {
  49. mViewHolder = (MyViewHolder) convertView.getTag();
  50. }
  51. BluetoothDevice currentListData = getItem(position);
  52. if (currentListData.getName()==null) {
  53. mViewHolder.tvname.setText("No name");
  54. }
  55. else{
  56. mViewHolder.tvname.setText(currentListData.getName());
  57. }
  58. mViewHolder.tvmac.setText(currentListData.getAddress());
  59. mViewHolder.tvRssi.setText(String.format("%ddBm", mRssis.get(position)));
  60. mViewHolder.tvBletype.setText(mBletype.get(position));
  61. return convertView;
  62. }
  63. private class MyViewHolder {
  64. TextView tvname, tvmac, tvRssi, tvSate, tvBletype;
  65. public MyViewHolder(View item) {
  66. tvname = (TextView)item.findViewById(R.id.name);
  67. tvmac = (TextView)item.findViewById(R.id.mac);
  68. tvRssi = (TextView)item.findViewById(R.id.rssi);
  69. tvBletype = (TextView)item.findViewById(R.id.bluetoothtype);
  70. }
  71. }
  72. public void clear() {
  73. deviceArrayList.clear();
  74. mRssis.clear();
  75. mBletype.clear();
  76. }
  77. public boolean addDevice (BluetoothDevice device) {
  78. boolean returnValue;
  79. if (!deviceArrayList.contains(device)) {
  80. deviceArrayList.add(device);
  81. returnValue = true;
  82. } else {
  83. returnValue = false;
  84. }
  85. return returnValue;
  86. }
  87. public void addBound() {
  88. Set<BluetoothDevice> bondedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
  89. if (bondedDevices != null)
  90. deviceArrayList.addAll(bondedDevices);
  91. }
  92. }

(5)增加一个广播接收类BtReceiver

这个类放在util包里面,下面这个是目录结构。

  1. package com.example.myapplication.util;
  2. import android.bluetooth.BluetoothA2dp;
  3. import android.bluetooth.BluetoothAdapter;
  4. import android.bluetooth.BluetoothDevice;
  5. import android.bluetooth.BluetoothHeadset;
  6. import android.content.BroadcastReceiver;
  7. import android.content.Context;
  8. import android.content.Intent;
  9. import android.content.IntentFilter;
  10. import android.util.Log;
  11. /**
  12. * 监听蓝牙广播-各种状态
  13. */
  14. public class BtReceiver extends BroadcastReceiver {
  15. private static final String TAG = BtReceiver.class.getSimpleName();
  16. private final Listener mListener;
  17. public BtReceiver(Context cxt, Listener listener) {
  18. mListener = listener;
  19. IntentFilter filter = new IntentFilter();
  20. filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙开关状态
  21. filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//蓝牙开始搜索
  22. filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙搜索结束
  23. filter.addAction(BluetoothDevice.ACTION_FOUND);//蓝牙发现新设备(未配对的设备)
  24. filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//在系统弹出配对框之前(确认/输入配对码)
  25. filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//设备配对状态改变
  26. filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);//最底层连接建立
  27. filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);//最底层连接断开
  28. filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); //BluetoothAdapter连接状态
  29. filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); //BluetoothHeadset连接状态
  30. filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); //BluetoothA2dp连接状态
  31. cxt.registerReceiver(this, filter);
  32. }
  33. @Override
  34. public void onReceive(Context context, Intent intent) {
  35. String action = intent.getAction();
  36. if (action == null)
  37. return;
  38. Log.i(TAG, "===" + action);
  39. BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  40. if (dev != null)
  41. Log.i(TAG, "BluetoothDevice: " + dev.getName() + ", " + dev.getAddress());
  42. switch (action) {
  43. case BluetoothAdapter.ACTION_STATE_CHANGED:
  44. int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
  45. Log.i(TAG, "STATE: " + state);
  46. break;
  47. case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
  48. break;
  49. case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
  50. break;
  51. case BluetoothDevice.ACTION_FOUND:
  52. short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MAX_VALUE);
  53. Log.i(TAG, "EXTRA_RSSI:" + rssi);
  54. mListener.foundDev(dev, rssi);
  55. break;
  56. case BluetoothDevice.ACTION_PAIRING_REQUEST: //在系统弹出配对框之前,实现自动配对,取消系统配对框
  57. /*try {
  58. abortBroadcast();//终止配对广播,取消系统配对框
  59. boolean ret = dev.setPin("1234".getBytes()); //设置PIN配对码(必须是固定的)
  60. } catch (Exception e) {
  61. e.printStackTrace();
  62. }*/
  63. break;
  64. case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
  65. Log.i(TAG, "BOND_STATE: " + intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0));
  66. break;
  67. case BluetoothDevice.ACTION_ACL_CONNECTED:
  68. break;
  69. case BluetoothDevice.ACTION_ACL_DISCONNECTED:
  70. break;
  71. case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:
  72. Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0));
  73. break;
  74. case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
  75. Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0));
  76. break;
  77. case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
  78. Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, 0));
  79. break;
  80. }
  81. }
  82. public interface Listener {
  83. void foundDev(BluetoothDevice dev, short devrssi);
  84. }
  85. }

(6)FirstFragment文件

(I)引入BtReceiver,修改主类

import com.example.myapplication.util.BtReceiver;
public class FirstFragment extends Fragment implements BtReceiver.Listener {

然后根据错误提示需要新增foundDev函数,这个函数是经典蓝牙搜索的结果

  1. @Override
  2. public void foundDev(BluetoothDevice dev, short devrssi) {
  3. mLeDeviceListAdapter.addDevice(dev);
  4. mRssis.add((int) devrssi);
  5. mfbletype.add("old");
  6. mLeDeviceListAdapter.notifyDataSetChanged();
  7. }

新建蓝牙相关的变量以及一些常量

  1. private static final String TAG = "FirstFragment";
  2. private final static int REQUEST_ENABLE_BT = 1;
  3. //获取主页面
  4. MainActivity mActivity;
  5. BluetoothManager btManager;
  6. BluetoothAdapter btAdapter;
  7. BluetoothLeScanner btScanner;
  8. private BtReceiver mBtReceiver;

 (II)获取主页面的Activity,因为我们的first页面是fragment页面,只能用主页面Activity去获取系统设备,第一个OnAttach是从Activity创建Fragment时调用的,第二个是OnDetach是从Fragment销毁返回到Activity时调用的。

  1. @Override
  2. public void onAttach(@NonNull Activity activity) {
  3. super.onAttach(activity);
  4. mActivity = (MainActivity) activity;
  5. }
  6. @Override
  7. public void onDetach() {
  8. super.onDetach();
  9. mActivity = null;
  10. }

(III)修改onCreateView函数页面创建方式

  1. // Inflate the layout for this fragment
  2. View view=inflater.inflate(R.layout.fragment_first, container, false);
  3. return view;

(IV)判断系统是否支持蓝牙,并获取,并跟蓝牙建立一个Intent数据链接,放在onCreateView函数return前面。

  1. btManager = (BluetoothManager)mActivity.getSystemService(Context.BLUETOOTH_SERVICE);
  2. btAdapter = btManager.getAdapter();
  3. if (btAdapter == null || !btAdapter.isEnabled()) {
  4. Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  5. startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
  6. }
  7. btScanner = btAdapter.getBluetoothLeScanner();

(V)FirstFragment继续增加变量

  1. final ArrayList<BluetoothDevice> availableBT = new ArrayList<>();
  2. private static List<String> mfbletype;
  3. private static List<Integer> mRssis;
  4. private static LeDeviceListAdapter mLeDeviceListAdapter;
  5. private static BluetoothGatt firstGatt = null;
  6. private static String conbletype = "";
  7. private static BluetoothDevice condev = null;

(VI)增加界面显示搜索到的设备,同样放置在onCreateView函数的return之前。

  1. mLeDeviceListAdapter = new LeDeviceListAdapter(mActivity.getApplicationContext(), availableBT, mRssis, mfbletype);
  2. final ListView listView_available = view.findViewById(R.id.listview2);
  3. listView_available.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  4. @Override
  5. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  6. firstGatt = null;
  7. conbletype = mfbletype.get(position);
  8. condev = mLeDeviceListAdapter.getItem(position);
  9. if (btAdapter.isDiscovering()) {
  10. btAdapter.cancelDiscovery();
  11. }
  12. NavHostFragment.findNavController(FirstFragment.this)
  13. .navigate(R.id.action_FirstFragment_to_SecondFragment);
  14. }
  15. });

(VII)增加一个蓝牙扫描设备的按钮,蓝牙扫描是最消耗能量的动作了,不符合BLE的思想所以一般手机都设置了30秒内扫描5次的限制,所以改成手动触发扫描,一次扫描时间挺长的,靠近一点等一等就会扫描到你要连接的蓝牙设备。

增加一个变量和常量

  1. private Handler mHandler;
  2. private static final long SCAN_PERIOD = 15000;
  1. mHandler = new Handler();
  2. mfbletype = new ArrayList<>();
  3. mRssis = new ArrayList<>();
  4. Button scan = view.findViewById(R.id.scan);
  5. scan.setOnClickListener(new View.OnClickListener() {
  6. @Override
  7. public void onClick(View v) {
  8. APP.toast("Scanning...", Toast.LENGTH_SHORT);
  9. mLeDeviceListAdapter.clear();
  10. mfbletype.clear();
  11. mRssis.clear();
  12. conbletype = "";
  13. condev = null;
  14. if (!btAdapter.isDiscovering()) {
  15. btAdapter.startDiscovery();
  16. }
  17. mHandler.postDelayed(new Runnable() {
  18. @Override
  19. public void run() {
  20. stopScanning();
  21. }
  22. },SCAN_PERIOD);
  23. scanLeDevice(true);
  24. mLeDeviceListAdapter.notifyDataSetChanged();
  25. listView_available.setAdapter(mLeDeviceListAdapter);
  26. }
  27. });

(VIII)onViewCreated这个原来用来控制页面一(蓝牙搜索页面)跳转到页面二(按钮控制页面)函数删除,之后采用点击对应的蓝牙设备直接跳转到页面二,然后增加缺少的一些函数,

添加已搜索到的设备到列表的回调函数leScanCallback,这个是BLE蓝牙搜索的结果。

  1. private final ScanCallback leScanCallback = new ScanCallback() {
  2. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  3. @Override
  4. public void onScanResult(int callbackType, ScanResult result) {
  5. if (!(mActivity == null || mActivity.isFinishing())) {
  6. mActivity.runOnUiThread(() -> {
  7. if (mLeDeviceListAdapter.addDevice(result.getDevice())) {
  8. mRssis.add(result.getRssi());
  9. mfbletype.add("ble");
  10. }
  11. mLeDeviceListAdapter.notifyDataSetChanged();
  12. });
  13. }
  14. }
  15. };

添加停止扫描函数stopScanning

  1. public void stopScanning() {
  2. Log.d(TAG, "stopping scanning" );
  3. AsyncTask.execute(new Runnable() {
  4. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  5. @Override
  6. public void run() {
  7. btScanner.stopScan(leScanCallback);
  8. }
  9. });
  10. }

添加扫描函数scanLeDevice

  1. private void scanLeDevice(final boolean enable) {
  2. if (enable) {
  3. mHandler.postDelayed(new Runnable() {
  4. @Override
  5. public void run() {
  6. stopScanning();
  7. }
  8. },SCAN_PERIOD);
  9. startScanning();
  10. } else {
  11. try {
  12. stopScanning();
  13. } catch (Exception e) {
  14. }
  15. }
  16. }

添加开始扫描函数startScanning

  1. public void startScanning() {
  2. //scan.setVisibility(View.INVISIBLE);
  3. //dc.setVisibility(View.VISIBLE);
  4. AsyncTask.execute(() -> btScanner.startScan(leScanCallback));
  5. }

(IX)onCreateView函数添加广播接收

  1. mBtReceiver = new BtReceiver(mActivity.getApplicationContext(), this);//注册蓝牙广播
  2. BluetoothAdapter.getDefaultAdapter().startDiscovery();

(X)onCreateView函数添加按钮的可见性

  1. Button button_first = view.findViewById(R.id.button_first);
  2. button_first.setVisibility(View.INVISIBLE);

3.页面设计

        上面的代码添加完毕后,还是存在一些报错,那是因为我们还缺少一些页面的组件元素。

(1) fragment_first.xml 文件

删除textview_first,包含activity_listview页面

<include layout="@layout/activity_listview" />

增加available、listview2、scan元素

  1. <TextView
  2. android:text="Available Devices"
  3. android:id="@+id/available"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"
  6. app:layout_constraintLeft_toLeftOf="parent"
  7. app:layout_constraintTop_toTopOf="parent"/>
  8. <ListView
  9. android:id="@+id/listview2"
  10. android:layout_width="match_parent"
  11. android:layout_height="500dp"
  12. android:layout_alignParentStart="true"
  13. android:layout_below="@+id/available"
  14. app:layout_constraintLeft_toLeftOf="parent"
  15. app:layout_constraintTop_toTopOf="parent"
  16. android:layout_marginTop="30dp"/>
  17. <Button
  18. android:id="@+id/scan"
  19. android:text="Scan Devices"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:layout_alignParentBottom="true"
  23. android:layout_alignParentLeft="true"
  24. app:layout_constraintBottom_toBottomOf="parent"
  25. app:layout_constraintLeft_toLeftOf="parent"
  26. android:layout_marginBottom="30dp"/>

修改button_first元素

  1. <Button
  2. android:id="@+id/button_first"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:text="@string/next"
  6. android:layout_toStartOf="@+id/scan"
  7. app:layout_constraintBottom_toBottomOf="parent"
  8. app:layout_constraintLeft_toRightOf="@+id/scan"
  9. android:layout_marginBottom="30dp"/>

(2) 增加activity_listview.xml 文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:background="#ffffff"
  6. android:gravity="center_vertical"
  7. android:orientation="vertical">
  8. <LinearLayout
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:orientation="horizontal"
  12. android:paddingBottom="8dp"
  13. android:paddingLeft="12dp"
  14. android:paddingRight="12dp"
  15. android:paddingTop="8dp">
  16. <LinearLayout
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_weight="1"
  20. android:orientation="vertical">
  21. <TextView
  22. android:id="@+id/name"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:ellipsize="end"
  26. android:singleLine="true"
  27. android:textSize="17sp" />
  28. <TextView
  29. android:id="@+id/mac"
  30. android:layout_width="wrap_content"
  31. android:layout_height="wrap_content"
  32. android:layout_below="@+id/name"
  33. android:ellipsize="end"
  34. android:singleLine="true"
  35. android:textColor="#999999"
  36. android:textSize="12sp" />
  37. <TextView
  38. android:id="@+id/rssi"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_below="@+id/mac"
  42. android:text=""
  43. android:textColor="#303030"
  44. android:textSize="12sp" />
  45. <TextView
  46. android:id="@+id/bluetoothtype"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_below="@+id/rssi"
  50. android:ellipsize="end"
  51. android:singleLine="true"
  52. android:textSize="12sp" />
  53. </LinearLayout>
  54. </LinearLayout>
  55. </LinearLayout>

(3)activity_main.xml文件

删除id为fab的图标

(4)其它文件

content_main.xml文件不用修改,fragment_second.xml保持上次的修改。

完整的项目地址--【AndroidStudio】经典蓝牙+BLE蓝牙搜索APP

4.连接设备调试

(1)连接手机

手机需要打开开发人员选项,开发人员选项大部分是通过点击关于手机的版本号6次以上打开的,再去系统和更新里面找到开发人员选项,然后将开发人员选项、USB调试打开。

 然后USB连接电脑后,选择传输文件选项。然后AndroidStudio里面就会显示手机的型号了。

(2)打开MainActivity文件

        右键选择Run MainActivity,不要直接点击Run和小三角键,会直接运行另外一个主类app。运行一次后你就可以直接点击小三角键了。

(3)实际效果

        请求打开蓝牙,定位权限获取,第一次获取位置信息权限之后,除非删除APP才会再次请求获取定位权限。

 

         点击Scan按钮,开启蓝牙扫描,扫描结果如下图,点击任何一个设备都会跳转至页面2。

   

         但要注意的是这个地方点击是没有加入连接蓝牙设备的,由于篇幅的原因,这个部分留到下一次再写。

        再附上完整的项目地址--【AndroidStudio】经典蓝牙+BLE蓝牙搜索APP


 总结

        蓝牙连接和控制属于AndroidStudio前期入门里面比较难的一类的了,后面可能还有屏幕的渲染,横竖屏的切换。下一次蓝牙连接文章都会涉及到。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/192355
推荐阅读
相关标签
  

闽ICP备14008679号