Android手机蓝牙互联,并传递数据。
2016-09-21 22:42
543 查看
今晚整理下,实验室没开门,只好在一教将就一下了
关于蓝牙,看了好些天,但是看完后想想也没啥,都是谷歌做好了的东西,我们只要用用API就ok了,哎。
首先,如果是互相传递数据的,两部android设备各自都必须充当两种角色。
1、服务端 2、客户端。
其实也不难理解,毕竟通信是两者之间建立的,而且必须实现收发并用。所以理所当然了,客户端发送消息给服务端。
两部设备是通过使用相同的UUID建立起一个Rfcomm什么的通道,这个通道连接两台设备以供数据的传递。
当然要如何建立呢?(我也不知道)
我们先分析客户端,他是通过Socket的一个主动连接函数connect()来请求服务端的连接(服务端接收到请求..才会有数据传递 后面再说),那么这个socket是怎样来的呢?
是通过device.createRfcommSocketToServiceRecord(UUID);来的,这个device是由你相连服务端的地址得到的,通过蓝牙适配器mBluetoothAdapter.getRemoteDevice(address);来的。address又是怎么来的呢? 是通过扫描附近蓝牙,被广播接收器接收到的。
好的整理一下,就是通过广播接收器扫描到附近的蓝牙设备(当然机智的你肯定准备好了两台设备) 然后能通过扫描到的设备得到他们的地址。通过这个地址就能实例化出device
然后Socket也就出来了。最后通过Socket.getOutputStream() 得到输出流,想输出流内写入数据 即可完成客户端的任务。
//以下是客户端负责发送消息的代码(布局和manifest文件自己添加以下,很简单)
package com.example.single_bt1; import android.app.Activity; 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.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; public class AsClient extends Activity implements OnItemClickListener { private static final String TAG = "MainActivity"; // 本地蓝牙适配器 private BluetoothAdapter mBluetoothAdapter; // 列表 private ListView lvDevices; // 存储搜索到的蓝牙 private List<String> bluetoothDevices = new ArrayList<String>(); // listview的adapter private ArrayAdapter<String> arrayAdapter; // UUID.randomUUID()随机获取UUID private final UUID MY_UUID = UUID .fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3"); // 连接对象的名称 private final String NAME = "LGL"; // 这里本身即是服务端也是客户端,需要如下类 private BluetoothSocket clientSocket; private BluetoothDevice device; // 输出流_客户端需要往服务端输出 private OutputStream os; private EditText et; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { // 获取本地蓝牙适配器 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 判断手机是否支持蓝牙 if (mBluetoothAdapter == null) { Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show(); finish(); } // 判断是否打开蓝牙 if (!mBluetoothAdapter.isEnabled()) { // 弹出对话框提示用户是后打开 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 1); // 不做提示,强行打开 // mBluetoothAdapter.enable(); } et = (EditText) findViewById(R.id.edit_input2); // 初始化listview lvDevices = (ListView) findViewById(R.id.lvDevices); lvDevices.setOnItemClickListener(this); // 获取已经配对的设备 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter .getBondedDevices(); // 判断是否有配对过的设备 if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { // 遍历到列表中 bluetoothDevices.add("已配对\n" + device.getName() + ":" + device.getAddress()); } } // adapter arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, bluetoothDevices); lvDevices.setAdapter(arrayAdapter); //启动服务 /** * 异步搜索蓝牙设备——广播接收 */ // 找到设备的广播 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); // 注册广播 registerReceiver(receiver, filter); // 搜索完成的广播 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); // 注册广播 registerReceiver(receiver, filter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); } // 广播接收器 private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 收到的广播类型 String action = intent.getAction(); // 发现设备的广播 if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 从intent中获取设备 BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 判断是否配对过 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { // 添加到列表 bluetoothDevices.add("未配对\n" + device.getName() + ":" + device.getAddress()); arrayAdapter.notifyDataSetChanged(); } // 搜索完成 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED .equals(action)) { // 关闭进度条 setProgressBarIndeterminateVisibility(true); setTitle("搜索完成!"); } } }; // 客户端 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 先获得蓝牙的地址和设备名 String s = arrayAdapter.getItem(position); // 单独解析地址 String address = s.substring(s.indexOf(":") + 1).trim(); // 主动连接蓝牙 try { // 判断是否在搜索,如果在搜索,就取消搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } try { // 获得远程设备 device = mBluetoothAdapter.getRemoteDevice(address); Log.e(TAG, "device:" + device); clientSocket = device .createRfcommSocketToServiceRecord(MY_UUID); // 连接 clientSocket.connect(); // 获得输出流 os = clientSocket.getOutputStream(); // 判断是否可以获得 if (device == null) { // 获得远程设备 4000 device = mBluetoothAdapter.getRemoteDevice(address); Log.e(TAG, "device:" + device); } // 开始连接 if (clientSocket == null) { clientSocket = device .createRfcommSocketToServiceRecord(MY_UUID); // 连接 clientSocket.connect(); // 获得输出流 os = clientSocket.getOutputStream(); } } catch (Exception e) { } // 如果成功获得输出流 if (os != null) { // os.write("Hello Bluetooth!".getBytes()); os.write(et.getText().toString().getBytes("GBK")); Log.e(TAG, "write"); et.setText(""); } } catch (Exception e) { } } }
接下来就是服务端了,服务端相比来说就稍微省事一点了,坐在那里等人来请求,所以他要一直在那里等,言下之意就是一个耗时操作,所以放在一个新的线程中是自然的事情。通过ServerScoket的accept()会产生一个socket负责与客户端的socket通信, 那么这个serversocket哪来的呢,直接上代码吧:
serverSocket = mBluetoothAdapter .listenUsingRfcommWithServiceRecord(NAME, MY_UUID); name是自己定义的,随便写就好(String类型)
然后就是通过serverSocket.getInputStream() 得到输入流,就能读出数据了。
package com.example.single_bt2_server;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
// 本地蓝牙适配器
private BluetoothAdapter mBluetoothAdapter;
// UUID.randomUUID()随机获取UUID
private final UUID MY_UUID = UUID
.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
// 连接对象的名称
private final String NAME = "LGL";
//线程类的实例
private AcceptThread ac;
// private EditText edit_Get;
private ListView list_Get;
private List<String> content = new ArrayList<String>();
private ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.received);
// edit_Get = (EditText) findViewById(R.id.edit_get);
initView();
}
private void initView() {
list_Get = (ListView) findViewById(R.id.list_get);
adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,content);
list_Get.setAdapter(adapter);
// 获取本地蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 判断手机是否支持蓝牙
if (mBluetoothAdapter == null) {
Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();
finish();
}
// 判断是否打开蓝牙
if (!mBluetoothAdapter.isEnabled()) {
// 弹出对话框提示用户是后打开
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
// 不做提示,强行打开
// mBluetoothAdapter.enable();
}
ac = new AcceptThread();
ac.start();
}
// 服务端,需要监听客户端的线程类
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, String.valueOf(msg.obj),
Toast.LENGTH_SHORT).show();
String result = String.valueOf(msg.obj);
// edit_Get.setText(String.valueOf(msg.obj));
content.add(result);
adapter.notifyDataSetChanged();
Log.e(TAG, msg.obj + ":服务端");
super.handleMessage(msg);
}
};
// 线程服务类
private class AcceptThread extends Thread {
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
// 输入 输出流
private OutputStream os;
private InputStream is;
public AcceptThread() {
try {
serverSocket = mBluetoothAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// 截获客户端的蓝牙消息
try {
socket = serverSocket.accept(); // 如果阻塞了,就会一直停留在这里
is = socket.getInputStream();
os = socket.getOutputStream();
while (true) {
synchronized (MainActivity.this) {
byte[] tt = new byte[is.available()];
if (tt.length > 0) {
is.read(tt, 0, tt.length);
Message msg = new Message();
msg.obj = new String(tt, "GBK");
Log.e(TAG, msg.obj + ":客户端");
handler.sendMessage(msg);
}
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
}
}
}
至于两者都有的角色 让我放到文件中吧,是网上参考
相关文章推荐
- Android手机蓝牙与单片机通信数据格式问题
- android之蓝牙通信(二)(蓝牙连接,数据传递)
- winXP系统通过蓝牙在笔记本和手机之间传递数据
- android通过蓝牙实现两台手机传输数据
- 关于Android中传递数据的一些讨论
- 关于Android中传递数据的一些讨论
- Android手机客户端与Servlet交换数据
- android中intent传递数据的方式
- Android 在两个 Activity 之间传递数据
- Android - Intent - 传递数据
- 【Android中级教程(三)之不同Activity之间的数据传递---Bundle对象的使用】的改进!
- Android开发循序渐进实例2--画面间数据传递例子
- Android中2个activity之间的数据传递方法
- Android两个Activity跳转并使用Bundle传递数据
- Android 2个activity 之间的数据传递
- 关于Android中传递数据的一些讨论
- Android数据传递相关内容概述
- Android中级教程(三)之不同Activity之间的数据传递---Bundle对象的使用!
- android手机怎样通过蓝牙传输文件
- android 应用程序Activity之间数据传递与共享的几种途径