Android无线蓝牙总结
一、基础知识:
①蓝牙的四层协议:
蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。
②蓝牙的操作:
Android提供蓝牙API来执行这些不同的操作。
1. 开关蓝牙
2. 扫描其他蓝牙设备
3. 获取配对设备列表
4. 连接到通过服务发现其他设备
③相关类的概要说明:
关于经典蓝牙(以下简称蓝牙)开发所用到的API都来自于android.bluetooth包中,本部分主要介绍相关类的概要说明:
1、BluetoothAdapter
BluetoothAdapter类的对象代表本地的蓝牙适配器。BluetoothAdapter是所有蓝牙交互操作的入口点,通过使用该类的对象,可以完成以下操作:
- 发现其他蓝牙设备
- 查询已配对的设备
- 通过已知的MAC地址实例化远程蓝牙设备
- 创建BluetoothServerSocket类(下文2.4)对象监听与其他蓝牙设备的通信。
2、BluetoothDevice
表示远程的蓝牙设备。使用该类对象可进行远程蓝牙设备的连接请求,以及查询该蓝牙设备的信息,例如名称,地址等。
3、BluetoothSocket
表示蓝牙socket的接口(与TCP Socket类似, 关于socket的概念请自行查阅计算机网络的相关内容)。该类的对象作为应用中数据传输的连接点。
4、BluetoothServerSocket
表示服务器socket,用来监听未来的请求(和TCP ServerSocket类似)。为了能使两个蓝牙设备进行连接,一个设备必须使用该类开启服务器socket,当远程的蓝牙设备请求该服务端设备时,如果连接被接受,BluetoothServerSocket将会返回一个已连接的BluetoothSocket类对象。
④蓝牙权限
1. android.permission.BLUETOOTH:
允许程序连接到已配对的蓝牙设备,请求连接/接收连接/传输数据需要改权限, 主要用于对配对后进行操作;
2. android.permission.BLUETOOTH_ADMIN :
允许程序发现和配对蓝牙设备, 该权限用来管理蓝牙设备, 有了这个权限, 应用才能使用本机的蓝牙设备, 主要用于对配对前的操作;
⑤BluetoothAdapter
BluetoothAdapter代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作
BluetoothAdapter.getDefaultAdapter()该静态方法可以获取该适配器对象.
⑥蓝牙的BluetoothAdapter .STATE 状态值 , 即开关状态
1.蓝牙关闭 int STATE_OFF //值为10, 蓝牙模块处于关闭状态;
2.蓝牙打开中 int STATE_TURNING_ON //值为11, 蓝牙模块正在打开;
3.蓝牙开启 int STATE_ON //值为12, 蓝牙模块处于开启状态;
4. 蓝牙开启中 int STATE_TURNING_OFF //值为13, 蓝牙模块正在关闭;
蓝牙开关状态顺序 : STATE_OFF –> STATE_TURNING_ON –> STATE_ON –>STATE_TURNING_OFF –> STATE_OFF;
⑦BluetoothAdapter SCAN_MOD状态值 ,即扫描状态
无功能状态 : int SCAN_MODE_NONE //值为20, 查询扫描和页面扫描都失效,
该状态下蓝牙模块既不能扫描其它设备, 也不可见;
扫描状态 : int SCAN_MODE_CONNECTABLE //值为21, 查询扫描失效, 页面扫描有效,
该状态下蓝牙模块可以扫描其它设备, 从可见性来说只对已配对的蓝牙设备可见, 只有配对的设备才能主动连接本设备;
可见状态 : int SCAN_MODE_CONNECTABLE_DISCOVERABLE //值为23, 查询扫描和页面扫描都有效;
⑧打开/关闭蓝牙的两种方法:
1.直接调用函数enable()去打开蓝牙设备 ;
2.系统API去打开蓝牙设备,该方式会弹出一个对话框样式的Activity供用户选择是否打开蓝牙设备。
//第一种启动蓝牙的方法,不推荐
//bluetoothAdapter.enable(); //第二种启动蓝牙的方法,推荐
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE);
//第二种方法要写数据回调方法
/**
* 数据回调方法
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "蓝牙已开启", Toast.LENGTH_SHORT).show();
// getMyBondedDevices();//获取绑定的蓝牙设备
adapter.notifyDataSetChanged();//刷新适配器
} else {
Toast.makeText(this, "蓝牙未开启", Toast.LENGTH_SHORT).show();
}
}
}
⑨关闭蓝牙,直接调用API 函数即disable()即可
public boolean disable ()
返回值:该函数会立即返回。
1.true 表示关闭操作成功
2. false 表示蓝牙操作失败
①、当前蓝牙已经关闭 ; ②、其他一些异常情况
⑩扫描蓝牙设备
1.public boolean startDiscovery ()
功能: 扫描蓝牙设备的开启
注意: 如果蓝牙没有开启,该方法会返回false ,即不会开始扫描过程。 2.public boolean cancelDiscovery ()
功能: 取消扫描过程。
注意: 如果蓝牙没有开启,该方法会返回false。 3.public boolean isDiscovering ()
功能: 是否正在处于扫描过程中。
注意: 如果蓝牙没有开启,该方法会返回false。
这里要特别注意,蓝牙扫描的时候,它会发出系统的广播,这是我们就要创建广播接收者来接收数据,数据里面就有蓝牙的设备对象和名称等等,广播也是蓝牙知识的重中之重。
(十一)蓝牙的广播
Action值 | 说明 |
---|---|
ACTION_STATE_CHANGED | 蓝牙状态值发生改变 |
*ACTION_SCAN_MODE_CHANGED | 蓝牙扫描状态(SCAN_MODE)发生改变* |
ACTION_DISCOVERY_STARTED | 蓝牙扫描过程开始 |
ACTION_DISCOVERY_FINISHED | 蓝牙扫描过程结束 |
ACTION_LOCAL_NAME_CHANGED | 蓝牙设备Name发生改变 |
ACTION_REQUEST_DISCOVERABLE | 请求用户选择是否使该蓝牙能被扫描 |
如果蓝牙没有开启,用户点击确定后,会首先开启蓝牙,继而设置蓝牙能被扫描。
Action值: ACTION_REQUEST_ENABLE // 请求用户选择是否打开蓝牙
创建广播接收者:
/**
* 广播接收者的创建
*/
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//获取设备的发送的广播
//做数据处理
}
};
注册广播接收者:
/**
* 广播的注册,注意这里Action可以添加多个
*/
@Override
protected void onResume() {
super.onResume();
//添加蓝牙广播的Action,发现蓝牙设备时的Action
IntentFilter intentFilter = new
IntentFilter(BluetoothDevice.ACTION_FOUND);
//添加蓝牙广播的Action,蓝牙设备扫描完毕时的Action
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, intentFilter);//注册广播接收者
}
广播的注销:
/**
* 广播的停止
*/
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);//取消广播
}
一般监听发现蓝牙和蓝牙扫描完成的广播就可以了。 通过广播接收数据后,再对数据进行处理。就可以看到我们手机上显示的蓝牙设设备名称和其他信息。
(十二)获取蓝牙的相关信息的方法
1.public String getName ()
功能:获取蓝牙设备Name
2.public String getAddress ()
功能:获取蓝牙设备的硬件地址(MAC地址),例如:00:11:22:AA:BB:CC
3.public boolean setName (String name)
功能:设置蓝牙设备的Name。
4.public SetgetBondedDevices ()
功能:获取与本机蓝牙所有绑定的远程蓝牙信息,以BluetoothDevice类实例(稍后讲到)返回。
注意:如果蓝牙未开启,该函数会返回一个空集合 。
5.public static boolean checkBluetoothAddress (String address)
功能: 验证蓝牙设备MAC地址是否有效。所有设备地址的英文字母必须大写,48位,形如:00:43:A8:23:10:F1 。
返回值: true 设备地址有效,false 设备地址无效
6.public BluetoothDevice getRemoteDevice (String address)
功能:以给定的MAC地址去创建一个 BluetoothDevice 类实例(代表远程蓝牙实例)。即使该蓝牙地址不可见,也会产生 一个BluetoothDevice 类实例。
返回:BluetoothDevice 类实例 。注意,如果该蓝牙设备MAC地址不能被识别,其蓝牙Name为null。
异常:如果MAC address无效,抛出IllegalArgumentException。
使用上面的方法就可以对蓝牙进行扫描显示。但是要使用蓝牙通信就要使用到Socket编程了。
二.蓝牙Socket通信
(一)UUID
在蓝牙中,每个服务和服务属性都唯一地由 全局唯一标识符 ,Universally Unique Identifier(UUID)来校验。正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。UUID类可表现为短整形(16或32位)和长整形(128 位)UUID。他提供了分别利用String和16位或32位数值来创建类的构造函数,提供了一个可以比较两个UUID(如果两个都是128位)的方法,还有一个可以转换一个UUID为一个字符串的方法。UUID实例是不可改变的(immutable),只有被UUID标示的服务可以被发现。
UUID的格式被分成5段,其中中间3段的字符数相同,都是4个,第1段是8个字符,最后一段是12个字符。所以UUID实际上是8个-4个-4个-4个-12个的字符串。
UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。两个蓝牙设备进行连接时需要使用同一个UUID, 这是一个服务的唯一标识,而且这个UUID的值必须是
00001101-0000-1000-8000-00805F9B34FB
上面这个UUID,直接复制使用就可以了。
两个手机,其中一个设置为服务器,然后点击连接的手机,就可以进行消息发送和接收了。
上面只是实现文本通信,文本也只是进行简单处理。
三、项目代码
权限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--6.0以上才要加的额外权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="open"
android:text="开启蓝牙" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="close"
android:text="关闭蓝牙" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="found"
android:text="暴露自己的设备名称" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="scan"
android:text="扫描蓝牙设备" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="createServer"
android:text="设置为蓝牙服务端" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="listen"
android:text="监听数据的接收" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <EditText
android:id="@+id/et_send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:singleLine="true" /> <Button
android:id="@+id/btn_send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="send"
android:text="send" />
</LinearLayout> <ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <TextView
android:id="@+id/tv_show"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> <TextView
android:id="@+id/tv_show_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right" /> <ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
可读写流的类
package com.example.lifen.bluetoothdemo; /**
* Created by LiFen on 2018/1/2.
*/ import android.bluetooth.BluetoothSocket;
import android.util.Log; import java.io.InputStream;
import java.io.OutputStream; /**
* 在子线程中进行读写操作
*/
public class RWStream extends Thread { InputStream is;//输入流
OutputStream os;//输出流 //蓝牙的Socket对象
private final BluetoothSocket socket; //通过构造方法传入Socket对象
public RWStream(BluetoothSocket socket) {
this.socket = socket;
} @Override
public void run() {
super.run();
try {
is = socket.getInputStream();//获取Socket的输入流
os = socket.getOutputStream();//获取Socket的输出流 byte[] buf = new byte[1024];
int len = 0;
Log.e("TAG", "-----------开始读取----(is==null) " + (is == null));
while (socket.isConnected()) {//当Socket是连接状态时,就一直进行数据的读取
while ((len = is.read(buf)) != -1) {
String message = new String(buf, 0, len);
//获取流里面的数据
Log.e("TAG", "----------" + message);
//如果在另一端设置的接口对象,那么就传递数据
if (dateShow != null) {
dateShow.getMessager(message);
}
}
}
} catch (Exception e) {
Log.e("TAG", "-----------线程异常");
}
} /**
* 数据的写入
*/
public void write(String msg) {
Log.e("TAG", "--------os!=null " + (os != null));
if (os != null) {
try {
//Socket数据的写入
os.write(msg.getBytes());
//刷新输出流数据
os.flush();
} catch (Exception e) {
Log.e("TAG", "---写入--------异常" + e.getMessage());
}
}
} /**
* 定义接口实现数据回调
*/
interface DataShow {
//返回数据,读取到的字符串,传递过去
void getMessager(String message); } //定义接口对象
DataShow dateShow; //接口的对象的设置方法
public void setDataShow(DataShow dateShow) {
this.dateShow = dateShow;
}
}
蓝牙服务器端(Socket服务端)的设计
package com.example.lifen.bluetoothdemo; /**
* Created by LiFen on 2018/1/2.
*/ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.util.Log; import java.io.IOException; /**
* 蓝牙设置的服务器端
*/ public class BlueServer extends Thread {
//可读写数据的对象
RWStream rwStream; public RWStream getRwStream() {
return rwStream;
} //蓝牙设备管理器
private final BluetoothAdapter adapter; //通过构造方法传入设置管理器
public BlueServer(BluetoothAdapter adapter) {
this.adapter = adapter;
} //线程内的任务
@Override
public void run() {
super.run();
try {
//创建蓝牙服务端的Socket,这里第一个参数是服务器的名称,第二个参数是UUID的字符串的值
BluetoothServerSocket socket = adapter.listenUsingRfcommWithServiceRecord("server", MainActivity.uuid);
Log.e("TAG", "--------------->>开始监听客户端连接");
//获取蓝牙客户端对象,这是一个同步方法,用客户端接入才有后面的操作
BluetoothSocket client = socket.accept();
Log.e("TAG", "--------------->>有客户端接入");
//获取可读可写对象
rwStream = new RWStream(client);
//开始可读可写线程的操作,这里是一直在读取数据的状态
rwStream.start();
} catch (IOException e) {
e.printStackTrace();
} }
}
主方法类的设计
package com.example.lifen.bluetoothdemo; import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import static android.util.Log.e; /**
* 蓝牙的使用示例
*/
public class MainActivity extends AppCompatActivity { //控制蓝牙设备的对象
BluetoothAdapter bluetoothAdapter;
//布局内的ListView控件
ListView listView;
TextView tv_show;
TextView tv_show_service;
EditText et_send;
Button btn_send;
ArrayAdapter adapter;//适配器对象的定义
//蓝牙设备的对象的集合
ArrayList<BluetoothDevice> devices = new ArrayList<>();
//设备的名称集合
ArrayList<String> deviceNames = new ArrayList<>();
//手机蓝牙的UUID固定值
public static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final int REQUEST_LOCATION = 1000;//手机动态请求权限的请求码
private static final int REQUEST_ENABLE = 1001;//启动蓝牙设备的请求码
private static final int REQUEST_DISCOVER_MYSELF = 1002;//设置自身蓝牙设备可被发现的请求码 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
listView = (ListView) findViewById(R.id.lv);
tv_show = (TextView) findViewById(R.id.tv_show);
tv_show_service = (TextView) findViewById(R.id.tv_show_service);
et_send = (EditText) findViewById(R.id.et_send);
btn_send = (Button) findViewById(R.id.btn_send);
//创建适配器,使用系统布局
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, deviceNames);
//给ListView设置适配器
listView.setAdapter(adapter);
//判断是否有了权限
checkPermission();
//给ListView设置点击事件,点击对应的条目就创建对应的客户端,并经行数据的读取和写入
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//连接服务器
connServer(devices.get(position));
}
}); } /**
* 打开蓝牙设备
*/
public void open(View view) {
//不推荐
//bluetoothAdapter.enable();
//推荐
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE);
} /**
* 关闭蓝牙设备
*/
public void close(View view) {
bluetoothAdapter.disable();//关闭
//擦除页面数据
deviceNames.clear();
adapter.notifyDataSetChanged();
} /**
* 扫描蓝牙设备
*/
public void scan(View view) { if (bluetoothAdapter.isEnabled()) {
//先清除页面数据!
devices.clear();
deviceNames.clear(); //使用广播的方法去获取设备,这里就要动态创建广播,并进行接听了
//定义一个系统规定action的广播,
//当系统没扫描到一个蓝牙设备就会发送一条广播
// 当系统做完扫描后,系统会发送广播,你只需在广播接收者做好处理
bluetoothAdapter.startDiscovery();
} else {
Toast.makeText(this, "请先开启蓝牙", Toast.LENGTH_SHORT).show();
}
} /**
* 让自身蓝牙设备可被发现
*/
public void found(View view) {
getMyBondedDevices();
if (bluetoothAdapter.isDiscovering()) {//如果蓝牙设置正在扫描
Toast.makeText(this, "正在扫描,别急", Toast.LENGTH_SHORT).show();
} else {
//这里可以设置显示自己蓝牙设备的时间,默认是300秒,也可以自定义单位是秒
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);
startActivityForResult(intent, REQUEST_DISCOVER_MYSELF);
}
} /**
* 开启蓝牙服务的服务端
*/
boolean isServer = false;//默认是普通客户端
BlueServer server;//创建蓝牙服务器的对象,在服务器做相关操作 public void createServer(View view) {
server = new BlueServer(bluetoothAdapter);
server.start();
isServer = true;//设置为服务端
} /**
* 发送数据
*/
public void send(View view) {
String et = et_send.getText().toString();//获取输入框的数据
//给另一端写入数据
write(et);
} /**
* 数据的传递
*/
public void write(String msg) {
if (isServer) {//服务器的写数据
btn_send.setText("服务器");
handlerSendMessager(1, msg);
e("TAG", "----------(server != null && server.getRwStream() != null) " + (server != null && server.getRwStream() != null));
if (server != null && server.getRwStream() != null) {
server.getRwStream().write(msg);
}
} else {//客户端的写数据
btn_send.setText("客户端");
handlerSendMessager(2, msg);
if (client != null) {
client.write(msg);
}
}
} /**
* 监听数据的接收
*/
public void listen(View view) { //服务器的监听数据
if (server != null) {
server.getRwStream().setDataShow(new RWStream.DataShow() {
@Override
public void getMessager(final String message) {
//要在主线程中改变UI
Log.e("TAG", "-------listen---Service" + message);
handlerSendMessager(2, message);
}
});
//客户端的监听数据
} else if (client != null) {
client.setDataShow(new RWStream.DataShow() {
@Override
public void getMessager(final String message) {
//要在主线程中改变UI
e("TAG", "-------listen---client" + message);
handlerSendMessager(1, message);
}
});
}
} /**
* Handler包装类
*/
private void handlerSendMessager(int what, String messge) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = messge;
handler.sendMessage(msg);
} /**
* 创建Handler对象用于线程间通信
*/
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//显示数据在文本中
if (msg.what == 1) {
//服务器的数据在右边
tv_show_service.setTextColor(Color.RED);
tv_show_service.setTextSize(20);
tv_show_service.append(msg.obj + "\n");
} else {
//客户端的数据在左边
tv_show.setTextColor(Color.BLUE);
tv_show.setTextSize(20);
tv_show.append(msg.obj + "\n");
} }
}; /**
* 客户端连接服务器
*/
RWStream client; private void connServer(BluetoothDevice device) {
try {
//创建蓝牙客户端的Socket对象,这里是类BluetoothSocket,服务端是BluetoothServerSocket
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
socket.connect();//连接Socket
//创建可读写的客户对象,传入Socket对象
client = new RWStream(socket);
//开始客户端的线程
client.start();
} catch (IOException e) {
e.printStackTrace();
} } /**
* 判断是否有蓝牙的权限,如果手机系统是6.0以上的就要动态创建权限
*/
private void checkPermission() {
if (Build.VERSION.SDK_INT >= 23) {
//
int check = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
if (check != PackageManager.PERMISSION_GRANTED) {
//请求权限
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
}
}
} /**
* 动态请求权限后,返回页面时的回调方法
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限已获取", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "权限未获取", Toast.LENGTH_SHORT).show();
finish();//关闭页面
}
} /**
* 数据回调方法
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "蓝牙已开启", Toast.LENGTH_SHORT).show();
getMyBondedDevices();//获取绑定的蓝牙设备
adapter.notifyDataSetChanged();//刷新适配器
} else {
Toast.makeText(this, "蓝牙未开启", Toast.LENGTH_SHORT).show();
}
} else { }
} /**
* 获取已经绑定的蓝牙设置
*/
private void getMyBondedDevices() {
//获取所有已经绑定了的设备
deviceNames.clear();//清除设备名称的集合
devices.clear();//清除蓝牙设备对象的集合
if (bluetoothAdapter.getBondedDevices() != null) {//如果蓝牙适配器对象不为空时
//获取里面的数据的对象
List<BluetoothDevice> liset = new ArrayList<>(bluetoothAdapter.getBondedDevices());
devices.addAll(liset);
//拿到适配器对象的名称数据
for (BluetoothDevice device : liset) {
deviceNames.add(device.getName());
}
}
} /**
* 广播的注册
*/
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
//添加蓝牙广播的Action
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, intentFilter);//注册广播接收者
} /**
* 广播的停止
*/
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);//取消广播
} /**
* 广播接收者的创建
*/
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//获取设备的发送的广播
if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
Toast.makeText(context, "蓝牙扫描完毕", Toast.LENGTH_SHORT).show();
} else {
//获取蓝牙设置对象
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//把对象和名称放到对应的集合中
devices.add(device);
deviceNames.add(TextUtils.isEmpty(device.getName()) ? "未命名" : device.getName());
adapter.notifyDataSetChanged();
}
}
}; }
本项目下载:http://download.csdn.net/download/qq_36726507/10185756
Android无线蓝牙总结的更多相关文章
- Android 串口蓝牙通信开发Java版本
Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...
- Android 低功耗蓝牙BLE 开发注意事项
基本概念和问题 1.蓝牙设计范式? 当手机通过扫描低功耗蓝牙设备并连接上后,手机与蓝牙设备构成了客户端-服务端架构.手机通过连接蓝牙设备,可以读取蓝牙设备上的信息.手机就是客户端,蓝牙设备是服务端. ...
- ubuntu16.04连接android手机蓝牙共享网络热点
最近的想要用android手机蓝牙共享wifi网络给ubuntu16.04系统用,查了好多资料,发现网上很少有有用的.自己实践后分享如下. 第一步:手机与电脑配对: 该步骤比较简单,网 ...
- Android BLE 蓝牙编程(一)
最近在研究这个,等我有时间来写吧! 终于在端午节给自己放个假,现在就来说说关于android蓝牙ble的 最近的学习成果吧!! 需要材料(写个简单教程吧--关于小米手环的哦!嘿嘿) Android 手 ...
- 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程
原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ UART HCI_UART H4 HCI L2CAP ...
- 【转】Android低功耗蓝牙应用开发获取的服务UUID
原文网址:http://blog.csdn.net/zhangjs0322/article/details/39048939 Android低功耗蓝牙应用程序开始时获取到的蓝牙血压计所有服务的UUID ...
- Android ble 蓝牙4.0 总结
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- 【源代码】基于Android和蓝牙的单片机温度採集系统
如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 STC89C52单片机通过HC-06蓝牙模块与Android手机通信实例- 基于And ...
- 锅巴视频工作室 ----------------android端蓝牙测试demo--app
android端蓝牙测试demo--app 这个是为一个客户做蓝牙项目时的一个测试demo,用来测试蓝牙单片机的收发情况,代码中没有做一些兼容性测试,请理解 锅巴视频工作室,专注于android视频相 ...
随机推荐
- linux-linnode满了的提示
线上有一台web服务器磁盘检测告警了,提示空间不足,登到服务器查看 <ignore_js_op> touch:cannot touch `furm.html': No space left ...
- VUE 高德地图选取地址组件开发
高德地图文档地址 http://lbs.amap.com/api/lightmap/guide/picker/ 结合步骤: 1.通过iframe内嵌引入高德地图组件 key就选你自己申请的key &l ...
- lavarel mongo 操作
本人使用环境 Ubuntu 18.04 LTS php7.2 lavarel5.5 mongodb的安装 mongodb 服务的安装 这个链接中有最全面最新的安装文档 https://docs ...
- ros有一个比较安全的登录方案:二次登录防火墙
原文: https://www.winbox.org/ /ip firewall address-list add address=10.0.0.0/8 list=login /ip firewall ...
- 网络之OSI七层协议模型、TCP/IP四层模型
13.OSI七层模型各层分别有哪些协议及它们的功能 在互联网中实际使用的是TCP/IP参考模型.实际存在的协议主要包括在:物理层.数据链路层.网络层.传输层和应用层.各协议也分别对应这5个层次而已. ...
- KPPW2.5 漏洞利用--CSRF
kppw2.5 CSRF漏洞复现 漏洞说明 http://192.168.50.157/kppw25/index.php?do=user&view=message&op=send 收件 ...
- Android ScrollView嵌套Recyclerview滑动卡顿,松手即停问题解决;
假如你的布局类似这样的: <ScrollView android:layout_width="match_parent" android:layout_height=&quo ...
- JavaWeb——tomcat manager 403 Access Denied .You are not authorized to view this page.
403 Access Denied You are not authorized to view this page. If you have already configured the Manag ...
- vs与linux的交叉编译环境搭建
很久之前就想写一个linux服务器,但是对linux的vim编译工具又不是很熟,只能在win环境下写好代码拷贝到linux环境下编译运行,现在VS出了一个插件可以对linux代码远程在linux环境下 ...
- !!字体图标(iconfont、Fontello 、雪碧图生成工具。Glyphicons、fontawesome 等)。 图片压缩
http://www.iconfont.cn/ 阿里巴巴矢量图标库 iconfont http://fontawesome.io fontawesome图标 http://www.bootcss.c ...