Android:经典蓝牙开发
来源:互联网 发布:c语言编译器安卓中文版 编辑:程序博客网 时间:2024/06/09 20:38
前言:
参加工作也有两年了,一直没什么机会接触蓝牙这一块的开发,特地找时间实践了一下。一开始本来是想尝试BLE的(毕竟是主流了),但是用了两台手机发现都不支持,只好先转战经典蓝牙。
关于API这里就不赘述了,网上已经总结的很好。这里简单实现一个小功能,给出源码大家共同学习。
1)使用前要确保蓝牙的打开等,这里的处理可能有bug,而且先前连接过的要到系统设置里取消配对才能搜索得出来。
2)SDK和系统的版本差异这个没特别的去试验,不一定能运行,这一点相信大家是很有经验的了。
一.服务端
1)服务端的话就是等待链接,链接成功之后点击发送图片会调用摄像头拍照之后将图像发送给客户端。
2)连接监听,输入流读数据都是阻塞的,这里都是开一个线程操作。
3)IO流在读取文件的时候一般我们都是判断是否读到-1为结束标志,但是socket的有所不同,输入流并不知道什么时候读到尾了(试过在最后写一个换行符,但是没用)。这里采 取的方法是客户端写入的时候在头四个字节写入图片的byte[]数组长度,那么服务端先读头四个字节得到文件的长度,再根据接受数据的总长度判断是否结束,基于这一点, 我们也可以很容易写出一个进度条的效果。
public class MainActivity extends AppCompatActivity { private final String MYUUID = "00001101-0000-1000-8000-00805F9B34FB"; private final String TAG = "Bluetooth"; private BluetoothAdapter blueAdapter; private BluetoothSocket socket; private InputStream is; private OutputStream os; private ReadThread readThread; private Button btnSendPic; private ImageView imgView; private byte[] bitmapBuffer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); blueAdapter = BluetoothAdapter.getDefaultAdapter(); if (blueAdapter == null) return; btnSendPic = (Button) findViewById(R.id.button_send_pic); imgView = (ImageView) findViewById(R.id.pic); if (btnSendPic != null) { btnSendPic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, 100); } }); } Thread t = new Thread(new Runnable() { @Override public void run() { try { BluetoothServerSocket serverSocket = blueAdapter.listenUsingRfcommWithServiceRecord("my socket", UUID.fromString(MYUUID)); socket = serverSocket.accept(); if (socket.isConnected()) { is = socket.getInputStream(); os = socket.getOutputStream(); readThread = new ReadThread(); readThread.start(); } } catch (IOException e) { e.printStackTrace(); } } }); t.start(); } public static byte[] readStream(InputStream inStream) throws Exception { if (inStream.available() <= 0) return null; byte[] head = new byte[4]; byte[] buffer = new byte[1024]; int len = -1; int length = 0; inStream.read(head); int scrLength = bytesToInt(head, 0); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); while ((len = inStream.read(buffer)) != -1) { length = length + len; outStream.write(buffer, 0, len); if (length >= scrLength) break; } byte[] data = outStream.toByteArray(); outStream.close(); return data; } public static byte[] intToBytes(int value) { byte[] src = new byte[4]; src[3] = (byte) ((value >> 24) & 0xFF); src[2] = (byte) ((value >> 16) & 0xFF); src[1] = (byte) ((value >> 8) & 0xFF); src[0] = (byte) (value & 0xFF); return src; } public static int bytesToInt(byte[] src, int offset) { int value; value = (int) ((src[offset] & 0xFF) | ((src[offset + 1] & 0xFF) << 8) | ((src[offset + 2] & 0xFF) << 16) | ((src[offset + 3] & 0xFF) << 24)); return value; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == Activity.RESULT_OK) { Bundle bundle = data.getExtras(); Bitmap map = (Bitmap) bundle.get("data"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); map.compress(Bitmap.CompressFormat.JPEG, 10, baos); byte[] picData = baos.toByteArray(); if (socket.isConnected() && os != null) { try { os.write(intToBytes(picData.length)); os.write(picData); os.flush(); } catch (IOException e) { e.printStackTrace(); } } } } private class ReadThread extends Thread { @Override public void run() { super.run(); while (true) { if (socket != null && is != null) { try { final byte[] bitmapBuffer = readStream(is); if (bitmapBuffer != null && bitmapBuffer.length > 0) { runOnUiThread(new Runnable() { @Override public void run() { if (imgView != null) { imgView.setImageBitmap(BitmapFactory.decodeByteArray(bitmapBuffer, 0, bitmapBuffer.length)); } } }); } } catch (Exception e) { } } } } }}
二.客户端
1)点击扫面之后会把结果放到一个列表里,再点击列表项就能连接配对了,这里配对用的还是系统的。
2)其他逻辑和服务端的差不多了
public class MainActivity extends AppCompatActivity { private final String MYUUID = "00001101-0000-1000-8000-00805F9B34FB"; private final String TAG = "Bluetooth"; private BluetoothAdapter blueAdapter; private ContentAdapter contentAdapter; private ArrayList<BluetoothDevice> array; private BluetoothSocket clientSocket; private InputStream is; private OutputStream os; private Button btScan; private Button btSendPic; private ImageView imgView; private ListView listView; private byte[] bitmapBuffer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); blueAdapter = BluetoothAdapter.getDefaultAdapter(); if (blueAdapter == null) { return; } array = new ArrayList<BluetoothDevice>(); contentAdapter = new ContentAdapter(); imgView = (ImageView) findViewById(R.id.pic); btSendPic = (Button) findViewById(R.id.button_send_pic); if (btSendPic != null) { btSendPic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, 100); } }); } BlueReceiver receiver = new BlueReceiver(); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(receiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(receiver, filter); btScan = (Button) findViewById(R.id.btScan); btScan.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { blueAdapter.startDiscovery(); } }); listView = (ListView) findViewById(R.id.listview); if (listView != null) { listView.setAdapter(contentAdapter); } } public static byte[] intToBytes(int value) { byte[] src = new byte[4]; src[3] = (byte) ((value >> 24) & 0xFF); src[2] = (byte) ((value >> 16) & 0xFF); src[1] = (byte) ((value >> 8) & 0xFF); src[0] = (byte) (value & 0xFF); return src; } public static int bytesToInt(byte[] src, int offset) { int value; value = (int) ((src[offset] & 0xFF) | ((src[offset + 1] & 0xFF) << 8) | ((src[offset + 2] & 0xFF) << 16) | ((src[offset + 3] & 0xFF) << 24)); return value; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == Activity.RESULT_OK) { Bundle bundle = data.getExtras(); Bitmap map = (Bitmap) bundle.get("data"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); map.compress(Bitmap.CompressFormat.JPEG, 10, baos); byte[] picData = baos.toByteArray(); if (clientSocket.isConnected() && os != null) { try { os.write(intToBytes(picData.length)); os.write(picData); os.flush(); } catch (IOException e) { e.printStackTrace(); } finally { } } } } public static byte[] readStream(InputStream inStream) throws Exception { if (inStream.available() <= 0) return null; byte[] head = new byte[4]; byte[] buffer = new byte[1024]; int len = -1; int length = 0; inStream.read(head); int scrLength = bytesToInt(head, 0); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); while ((len = inStream.read(buffer)) != -1) { length = length + len; outStream.write(buffer, 0, len); if (length >= scrLength) break; } byte[] data = outStream.toByteArray(); outStream.close(); return data; } private class ReadThread extends Thread { @Override public void run() { super.run(); while (true) { if (clientSocket.isConnected() && is != null) { try { final byte[] bitmapBuffer = readStream(is); if (bitmapBuffer != null && bitmapBuffer.length > 0) { runOnUiThread(new Runnable() { @Override public void run() { if (imgView != null) { imgView.setImageBitmap(BitmapFactory.decodeByteArray(bitmapBuffer, 0, bitmapBuffer.length)); } } }); } } catch (Exception e) { } } } } } private class ContentAdapter extends BaseAdapter { @Override public int getCount() { return array.size(); } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(final int i, View view, ViewGroup viewGroup) { View v = getLayoutInflater().inflate(R.layout.list_item, null); Button bt = (Button) v.findViewById(R.id.button1); if (bt != null) { bt.setText(array.get(i).getName() + "," + array.get(i).getAddress()); bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Thread t = new Thread(new Runnable() { @Override public void run() { try { blueAdapter.cancelDiscovery(); clientSocket = array.get(i).createRfcommSocketToServiceRecord(UUID.fromString(MYUUID)); clientSocket.connect(); if (clientSocket.isConnected()) { os = clientSocket.getOutputStream(); is = clientSocket.getInputStream(); ReadThread thread = new ReadThread(); thread.start(); } } catch (IOException e) { e.printStackTrace(); } } }); t.start(); } }); } return v; } } private class BlueReceiver extends BroadcastReceiver { @Override public void onReceive(android.content.Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { array.add(device); contentAdapter.notifyDataSetChanged(); Log.v(TAG, "find device:" + device.getName() + "," + device.getAddress() + device.getUuids()); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED .equals(action)) { Log.v(TAG, "find over"); } } }}
源码下载,这里只给出主要的类和布局,大家最好自己构建项目,就不会有这么多编译上的问题。
https://github.com/SingleInstance/classic-bluetooth-for-Android
阅读全文
0 0
- Android:经典蓝牙开发
- android经典蓝牙开发
- android蓝牙开发之经典蓝牙
- Android经典蓝牙开发简介
- Android经典蓝牙开发简介
- Android蓝牙开发基础:经典蓝牙开发基础
- Android开发--蓝牙操作 经典蓝牙 扫描和连接
- Android 经典蓝牙用法
- Android连接经典蓝牙
- Android中经典蓝牙开发步骤 (流程)
- Android经典蓝牙开发简介(Google官网译文)
- 关于android 经典蓝牙开发 使用UUID连接的问题
- 蓝牙----Android的蓝牙开发
- Android 蓝牙开发-蓝牙通信
- Android蓝牙开发【三】蓝牙Hid开发
- Android蓝牙开发
- Android蓝牙应用开发
- Android蓝牙开发
- linux查看服务器网络状态
- VueJS项目
- JavaScript中属性的用法
- WebUi
- Java面向对象的知识点梳理
- Android:经典蓝牙开发
- bzoj2588Spoj 10628. Count on a tree 树上主席树
- CSDN机器学习笔记四 逻辑回归
- 二叉树的面试题总结
- ubuntu联网不稳定,时断时连问题的解决办法
- Fzu 2155 盟国【并查集的增删】裸题
- ubuntu下解压zip文件
- Retrofit使用 addInterceptor和addNetworkInterceptor的区别
- 整数排序 II