Android蓝牙搜索设备,向其发送数据并接收

本文介绍如何使用蓝牙Socket实现Android设备间的数据传输。通过客户端和服务端的Socket连接,完成搜索蓝牙设备、建立连接及发送数据的过程。

From:http://blog.youkuaiyun.com/liuyu973971883/article

/details/52495054

通过蓝牙传输数据Socket类似。在网络中使用SocketServerSocket控制客户端和服务端的数据读写。而蓝牙通讯也由客户端和服务端Socket来完成。蓝牙客户端SocketBluetoothSocket,蓝牙服务端SocketBluetoothServerSocket。这两个类都在Android.bluetooth包中

      

无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,UniversallyUnique Identifier).格式如下:

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

UUID的格式被分成5段,其中中间3段的字符数相同,都是4,第1段是8个字符,最后一段是12个字符。所以UUID实际上是一个8-4-4-4-12的字符串。

UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。


效果图:

搜索设备:


向一个设备发送数据

另一台设备收到了信息,并显示出来了:




——————————————————————————————————————

值得注意的是在建立连接的时候,设备、输出流、接口等变量需要是全局变量,否则方法执行完,就断开连接了。然后进行第二次发送数据就接收不到了。


下面我们就来做这个demo吧,在测试的时候需要手动开启蓝牙,如果需要自动开启蓝牙请查看我上一篇博客。

首先,必不可少的就是添加两个蓝牙权限:

[java]  view plain  copy
 print ?
  1. <uses-permission android:name="android.permission.BLUETOOTH"/>  
  2.     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>  


布局文件,由一个搜索按钮和一个listview组成,用于显示搜到的设备

activity_main.xml:

[java]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="fill_parent"  
  3.     android:layout_height="fill_parent"  
  4.     android:orientation="vertical" >  
  5.   
  6.     <Button  
  7.         android:layout_width="fill_parent"  
  8.         android:layout_height="wrap_content"  
  9.         android:onClick="onClick_Search"  
  10.         android:text="搜索" />  
  11.   
  12.     <ListView  
  13.         android:id="@+id/lvDevices"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="wrap_content" />  
  16.   
  17. </LinearLayout>  

代码文件

MainActivity.Java:

[java]  view plain  copy
 print ?
  1. package com.oak.learnbluetoothsocket;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import java.util.Set;  
  9. import java.util.UUID;  
  10. import android.os.Bundle;  
  11. import android.os.Handler;  
  12. import android.os.Message;  
  13. import android.app.Activity;  
  14. import android.bluetooth.BluetoothAdapter;  
  15. import android.bluetooth.BluetoothDevice;  
  16. import android.bluetooth.BluetoothServerSocket;  
  17. import android.bluetooth.BluetoothSocket;  
  18. import android.content.BroadcastReceiver;  
  19. import android.content.Context;  
  20. import android.content.Intent;  
  21. import android.content.IntentFilter;  
  22. import android.view.View;  
  23. import android.widget.AdapterView;  
  24. import android.widget.AdapterView.OnItemClickListener;  
  25. import android.widget.ArrayAdapter;  
  26. import android.widget.ListView;  
  27. import android.widget.Toast;  
  28.   
  29. public class MainActivity extends Activity implements OnItemClickListener {  
  30.     // 获取到蓝牙适配器  
  31.     private BluetoothAdapter mBluetoothAdapter;  
  32.     // 用来保存搜索到的设备信息  
  33.     private List<String> bluetoothDevices = new ArrayList<String>();  
  34.     // ListView组件  
  35.     private ListView lvDevices;  
  36.     // ListView的字符串数组适配器  
  37.     private ArrayAdapter<String> arrayAdapter;  
  38.     // UUID,蓝牙建立链接需要的  
  39.     private final UUID MY_UUID = UUID  
  40.             .fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");  
  41.     // 为其链接创建一个名称  
  42.     private final String NAME = "Bluetooth_Socket";  
  43.     // 选中发送数据的蓝牙设备,全局变量,否则连接在方法执行完就结束了  
  44.     private BluetoothDevice selectDevice;  
  45.     // 获取到选中设备的客户端串口,全局变量,否则连接在方法执行完就结束了  
  46.     private BluetoothSocket clientSocket;  
  47.     // 获取到向设备写的输出流,全局变量,否则连接在方法执行完就结束了  
  48.     private OutputStream os;  
  49.     // 服务端利用线程不断接受客户端信息  
  50.     private AcceptThread thread;  
  51.   
  52.     @Override  
  53.     protected void onCreate(Bundle savedInstanceState) {  
  54.         super.onCreate(savedInstanceState);  
  55.         setContentView(R.layout.activity_main);  
  56.         // 获取到蓝牙默认的适配器  
  57.         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  58.         // 获取到ListView组件  
  59.         lvDevices = (ListView) findViewById(R.id.lvDevices);  
  60.         // 为listview设置字符换数组适配器  
  61.         arrayAdapter = new ArrayAdapter<String>(this,  
  62.                 android.R.layout.simple_list_item_1, android.R.id.text1,  
  63.                 bluetoothDevices);  
  64.         // 为listView绑定适配器  
  65.         lvDevices.setAdapter(arrayAdapter);  
  66.         // 为listView设置item点击事件侦听  
  67.         lvDevices.setOnItemClickListener(this);  
  68.   
  69.         // 用Set集合保持已绑定的设备  
  70.         Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();  
  71.         if (devices.size() > 0) {  
  72.             for (BluetoothDevice bluetoothDevice : devices) {  
  73.                 // 保存到arrayList集合中  
  74.                 bluetoothDevices.add(bluetoothDevice.getName() + ":"  
  75.                         + bluetoothDevice.getAddress() + "\n");  
  76.             }  
  77.         }  
  78.         // 因为蓝牙搜索到设备和完成搜索都是通过广播来告诉其他应用的  
  79.         // 这里注册找到设备和完成搜索广播  
  80.         IntentFilter filter = new IntentFilter(  
  81.                 BluetoothAdapter.ACTION_DISCOVERY_FINISHED);  
  82.         registerReceiver(receiver, filter);  
  83.         filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);  
  84.         registerReceiver(receiver, filter);  
  85.   
  86.         // 实例接收客户端传过来的数据线程  
  87.         thread = new AcceptThread();  
  88.         // 线程开始  
  89.         thread.start();  
  90.     }  
  91.   
  92.     public void onClick_Search(View view) {  
  93.         setTitle("正在扫描...");  
  94.         // 点击搜索周边设备,如果正在搜索,则暂停搜索  
  95.         if (mBluetoothAdapter.isDiscovering()) {  
  96.             mBluetoothAdapter.cancelDiscovery();  
  97.         }  
  98.         mBluetoothAdapter.startDiscovery();  
  99.     }  
  100.   
  101.     // 注册广播接收者  
  102.     private BroadcastReceiver receiver = new BroadcastReceiver() {  
  103.         @Override  
  104.         public void onReceive(Context arg0, Intent intent) {  
  105.             // 获取到广播的action  
  106.             String action = intent.getAction();  
  107.             // 判断广播是搜索到设备还是搜索完成  
  108.             if (action.equals(BluetoothDevice.ACTION_FOUND)) {  
  109.                 // 找到设备后获取其设备  
  110.                 BluetoothDevice device = intent  
  111.                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
  112.                 // 判断这个设备是否是之前已经绑定过了,如果是则不需要添加,在程序初始化的时候已经添加了  
  113.                 if (device.getBondState() != BluetoothDevice.BOND_BONDED) {  
  114.                     // 设备没有绑定过,则将其保持到arrayList集合中  
  115.                     bluetoothDevices.add(device.getName() + ":"  
  116.                             + device.getAddress() + "\n");  
  117.                     // 更新字符串数组适配器,将内容显示在listView中  
  118.                     arrayAdapter.notifyDataSetChanged();  
  119.                 }  
  120.             } else if (action  
  121.                     .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {  
  122.                 setTitle("搜索完成");  
  123.             }  
  124.         }  
  125.     };  
  126.   
  127.     // 点击listView中的设备,传送数据  
  128.     @Override  
  129.     public void onItemClick(AdapterView<?> parent, View view, int position,  
  130.             long id) {  
  131.         // 获取到这个设备的信息  
  132.         String s = arrayAdapter.getItem(position);  
  133.         // 对其进行分割,获取到这个设备的地址  
  134.         String address = s.substring(s.indexOf(":") + 1).trim();  
  135.         // 判断当前是否还是正在搜索周边设备,如果是则暂停搜索  
  136.         if (mBluetoothAdapter.isDiscovering()) {  
  137.             mBluetoothAdapter.cancelDiscovery();  
  138.         }  
  139.         // 如果选择设备为空则代表还没有选择设备  
  140.         if (selectDevice == null) {  
  141.             //通过地址获取到该设备  
  142.             selectDevice = mBluetoothAdapter.getRemoteDevice(address);  
  143.         }  
  144.         // 这里需要try catch一下,以防异常抛出  
  145.         try {  
  146.             // 判断客户端接口是否为空  
  147.             if (clientSocket == null) {  
  148.                 // 获取到客户端接口  
  149.                 clientSocket = selectDevice  
  150.                         .createRfcommSocketToServiceRecord(MY_UUID);  
  151.                 // 向服务端发送连接  
  152.                 clientSocket.connect();  
  153.                 // 获取到输出流,向外写数据  
  154.                 os = clientSocket.getOutputStream();  
  155.   
  156.             }  
  157.             // 判断是否拿到输出流  
  158.             if (os != null) {  
  159.                 // 需要发送的信息  
  160.                 String text = "成功发送信息";  
  161.                 // 以utf-8的格式发送出去  
  162.                 os.write(text.getBytes("UTF-8"));  
  163.             }  
  164.             // 吐司一下,告诉用户发送成功  
  165.             Toast.makeText(this"发送信息成功,请查收"0).show();  
  166.         } catch (IOException e) {  
  167.             // TODO Auto-generated catch block  
  168.             e.printStackTrace();  
  169.             // 如果发生异常则告诉用户发送失败  
  170.             Toast.makeText(this"发送信息失败"0).show();  
  171.         }  
  172.   
  173.     }  
  174.   
  175.     // 创建handler,因为我们接收是采用线程来接收的,在线程中无法操作UI,所以需要handler  
  176.     Handler handler = new Handler() {  
  177.         @Override  
  178.         public void handleMessage(Message msg) {  
  179.             // TODO Auto-generated method stub  
  180.             super.handleMessage(msg);  
  181.             // 通过msg传递过来的信息,吐司一下收到的信息  
  182.             Toast.makeText(MainActivity.this, (String) msg.obj, 0).show();  
  183.         }  
  184.     };  
  185.   
  186.     // 服务端接收信息线程  
  187.     private class AcceptThread extends Thread {  
  188.         private BluetoothServerSocket serverSocket;// 服务端接口  
  189.         private BluetoothSocket socket;// 获取到客户端的接口  
  190.         private InputStream is;// 获取到输入流  
  191.         private OutputStream os;// 获取到输出流  
  192.   
  193.         public AcceptThread() {  
  194.             try {  
  195.                 // 通过UUID监听请求,然后获取到对应的服务端接口  
  196.                 serverSocket = mBluetoothAdapter  
  197.                         .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);  
  198.             } catch (Exception e) {  
  199.                 // TODO: handle exception  
  200.             }  
  201.         }  
  202.   
  203.         public void run() {  
  204.             try {  
  205.                 // 接收其客户端的接口  
  206.                 socket = serverSocket.accept();  
  207.                 // 获取到输入流  
  208.                 is = socket.getInputStream();  
  209.                 // 获取到输出流  
  210.                 os = socket.getOutputStream();  
  211.   
  212.                 // 无线循环来接收数据  
  213.                 while (true) {  
  214.                     // 创建一个128字节的缓冲  
  215.                     byte[] buffer = new byte[128];  
  216.                     // 每次读取128字节,并保存其读取的角标  
  217.                     int count = is.read(buffer);  
  218.                     // 创建Message类,向handler发送数据  
  219.                     Message msg = new Message();  
  220.                     // 发送一个String的数据,让他向上转型为obj类型  
  221.                     msg.obj = new String(buffer, 0, count, "utf-8");  
  222.                     // 发送数据  
  223.                     handler.sendMessage(msg);  
  224.                 }  
  225.             } catch (Exception e) {  
  226.                 // TODO: handle exception  
  227.                 e.printStackTrace();  
  228.             }  
  229.   
  230.         }  
  231.     }  
  232. }  
到这里,一个简单的蓝牙发送数据和接收数据就完成了,更多android方面的技术尽请期待。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值