android中的无线通信蓝牙
来源:互联网 发布:webrtc 源码介绍 编辑:程序博客网 时间:2024/05/23 13:41
一.蓝牙基础知识
蓝牙(Bluetooth)是一种短距离的无线通信技术标准。这个名子来源于10世纪丹麦国王Harald Blatand,英文名子是Harold Bluetooth。
(一)蓝牙的四层协议
蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。
(二)蓝牙的操作
Android提供蓝牙API来执行这些不同的操作。
1. 开关蓝牙
2. 扫描其他蓝牙设备
3. 获取配对设备列表
4. 连接到通过服务发现其他设备
(三)蓝牙权限
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);//第二种方法要写数据回调方法/** * 数据回调方法 */@Overrideprotected 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(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
(八)关闭蓝牙,直接调用API 函数即disable()即可。
public boolean disable ()
返回值:该函数会立即返回。
1.true 表示关闭操作成功
2. false 表示蓝牙操作失败 , ①、当前蓝牙已经关闭 ; ②、其他一些异常情况
(九)扫描蓝牙设备
1.public boolean startDiscovery () 功能: 扫描蓝牙设备的开启 注意: 如果蓝牙没有开启,该方法会返回false ,即不会开始扫描过程。 2.public boolean cancelDiscovery () 功能: 取消扫描过程。 注意: 如果蓝牙没有开启,该方法会返回false。 3.public boolean isDiscovering () 功能: 是否正在处于扫描过程中。 注意: 如果蓝牙没有开启,该方法会返回false。
这里要特别注意,蓝牙扫描的时候,它会发出系统的广播,这是我们就要创建广播接收者来接收数据,数据里面就有蓝牙的设备对象和名称等等,广播也是蓝牙知识的重中之重。
(十)蓝牙的广播
PS:如果蓝牙没有开启,用户点击确定后,会首先开启蓝牙,继而设置蓝牙能被扫描。
Action值: ACTION_REQUEST_ENABLE // 请求用户选择是否打开蓝牙
示例:
创建广播接收者:
/** * 广播接收者的创建 */private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //获取设备的发送的广播 //做数据处理 }};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
注册广播接收者
/** * 广播的注册,注意这里Action可以添加多个 */@Overrideprotected void onResume() { super.onResume();//添加蓝牙广播的Action,发现蓝牙设备时的Action IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//添加蓝牙广播的Action,蓝牙设备扫描完毕时的Action intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(receiver, intentFilter);//注册广播接收者}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
广播的注销
/** * 广播的停止 */@Overrideprotected void onPause() { super.onPause(); unregisterReceiver(receiver);//取消广播}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
一般监听发现蓝牙和蓝牙扫描完成的广播就可以了。
通过广播接收数据后,再对数据进行处理。就可以看到我们手机上显示的蓝牙设设备名称和其他信息。
(十一)获取蓝牙的相关信息的方法
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通信
关于Socket编程,之前有一篇Java的简介和使用示例:
http://blog.csdn.net/wenzhi20102321/article/details/52620323
(一)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,直接复制使用就可以了。
下面是蓝牙Socket使用示例:
三.蓝牙Socket通信示例
程序实现两台手机的蓝牙发送消息,并接受消息。这里的蓝牙是不需要网络支持的。
程序运行后,扫描蓝牙后的界面:
程序进行通信后的界面,要两个手机哦!
两个手机,其中一个设置为服务器,然后点击连接的手机,就可以进行消息发送和接收了。
上面只是实现文本通信,文本也只是进行简单处理。
程序设计代码:
(一)添加权限
<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" />
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
(二)布局文件的设计
<?xml version="1.0" encoding="utf-8"?><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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
(三)可读写流的类
package fuxi.bluetooth20;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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
(四)蓝牙服务器端(Socket服务端)的设计
package fuxi.bluetooth20;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(); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
(五)主方法类的设计
package fuxi.bluetooth20;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) { //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(); } } };}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
上面程序运行后就可以完成蓝牙通信了,上面程序设计中显示多个按钮是为了蓝牙的使用示范,实际程序中,可以减少扫描按钮,比如程序运行就打开蓝牙,监听数据的按钮的方法也是可以嵌入到程序当中。
本程序虽然可以进行简单通信,但是也是有一些bug的,比如没有按照上面的步骤操作,直接点击后面的按钮是会空指针的!逻辑处理没有完善。
如果要传输文件,或其他数据都是可以的,那就要对输入流和输出流进行设置了。
这里对Socket编程简单做几句介绍,其实Socket编程并不是很难理解。Socket编程一般需要一个服务端SocketServie和一个或多个客户端Socket,通过SocketService或Socket对象获取它的输入流实现对数据的读取,获取输出流实现对数据的写入。其中数据如果要一直读取就要写一个一直执行的子线程,让它一直在跑。
而Tcp/Udp编程就要用到ip地址和端口号了。Socket编程可以结合Tcp使用网络。
- android中的无线通信蓝牙
- Android中的蓝牙
- Android中的蓝牙系统
- Android中的蓝牙知识
- Android 中的蓝牙模块
- Android 设置中的蓝牙
- J2ME 中的无线通信协议
- android中的蓝牙那些事
- Android 蓝牙开发中的问题
- 无线通信中的小尺度衰落
- 无线通信
- 无线通信
- 无线通信
- 无线通信
- 浅谈红外、蓝牙、WIFI、NFC等无线通信的发展
- 无线通信原理及协议栈(ZigBee、蓝牙等)解析
- 无线通信原理及协议栈(ZigBee、蓝牙等)解析
- 嵌入式学习--work6 无线通信之蓝牙模块学习
- TextView长按复制-粘贴
- 用“Keras”11行代码构建CNN
- 文章标题
- 需求调研问卷的编写(2)
- sql server 的T-SQL 学习笔记(九)
- android中的无线通信蓝牙
- C/C++中的static关键字的易错点
- exercise5
- C# ASP.NET 解决方案开发微信公众号
- Discuz手机触屏版的帖子中图片无法放大查看
- spring mvc 给Controller添加事务
- Tomcat启动时加载数据到缓存--Web.xml里listener的加载顺序,优先初始化Spring IOC容器
- 关于android webview 的那些坑
- ArrayDeque