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视频相 ...
随机推荐
- Spring生态研习【一】:定时任务Spring-task
本系列具体研究一下spring生态中的重要或者常用的功能套件,今天从定时任务开始,主要是spring-task.至于quartz,下次找个时间再总结. 我的验证环境,是SpringCloud体系下,基 ...
- SpringBoot Web开发(5) 开发页面国际化+登录拦截
SpringBoot Web开发(5) 开发页面国际化+登录拦截 一.页面国际化 页面国际化目的:根据浏览器语言设置的信息对页面信息进行切换,或者用户点击链接自行对页面语言信息进行切换. **效果演示 ...
- js源生ajax
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ANSI编码导致的乱码
美帝那边的一个 donet 项目,打开后发现一段string里面各种乱码.一通折腾后发现是编码格式问题.这段string所在的类文件保存格式为ANSI,而不是VS默认的UTF-8. ANSI编码电脑是 ...
- Python——python读取xml实战,作业6(python programming)
cd_catalog.xml <?xml version="1.0" encoding="ISO-8859-1"?> <!-- Edited ...
- mysqldump备份与恢复笔记
mysql> show databases; +--------------------+ | Database | +--------------------+ | inf ...
- Java选择排序,插入排序,快速排序
public class Test { public static void main(String[] args) { int a[] = { 1, 2, 3, 4, 5 }; 选择排序(a); ...
- 格式化hdfs后,hadoop集群启动hdfs,namenode启动成功,datanode未启动
集群格式化hdfs后,在主节点运行启动hdfs后,发现namenode启动了,而datanode没有启动,在其他节点上jps后没有datanode进程!原因: 当我们使用hdfs namenode - ...
- Unable to complete the scan for annotations for web application [/wrs] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies.
tomcat启动报错:Jul 20, 2018 11:48:37 AM org.apache.catalina.core.ContainerBase addChildInternalSEVERE: C ...
- (2) linux文件系统简介
bin -- 存放可执行的命令程序 sbin -- 系统管理相关的命令程序 boot -- 存放启动相关的内容 dev -- 存放设备和硬件 etc -- 存放程序,系统的配置文件 home -- 存 ...