0.权限  AndroidManifest.xml

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<activity
android:name=".DeviceListActivity"
android:configChanges="screenSize|keyboardHidden|orientation"
android:launchMode="singleInstance"
android:screenOrientation="portrait"/>

1.设备列表布局  activity_device_list.xml (主要就一个listview了)

<?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"> <TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center"
android:text="扫描到的蓝牙"/> <ListView
android:id="@+id/listViewMessage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fastScrollEnabled="true"/> </LinearLayout>

2.设备列表java代码  DeviceListActivity.java

package de.bvb.bluetoothchat;

import android.app.Activity;
import android.app.Dialog;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import de.bvb.bluetoothchat.utils.BlueToothConnectCallback;
import de.bvb.bluetoothchat.utils.BluetoothDeviceInfo;
import de.bvb.bluetoothchat.utils.ClientUtil; /**
* Created by Administrator on 2017/06/01.
*/ public class DeviceListActivity extends Activity implements AdapterView.OnItemClickListener {
List<String> list;
ArrayAdapter<String> adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_list); ListView listView = (ListView) findViewById(R.id.listViewMessage); list = new ArrayList<>();
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this); ClientUtil.getInstance().onCreate(this);
ClientUtil.getInstance().setOnFoundUnBondDeviceListener(new ClientUtil.OnFoundUnBondDeviceListener() {
@Override
public void foundUnBondDevice(BluetoothDevice unBondDevice) {
list.add(unBondDevice.getName() + "|" + unBondDevice.getAddress());
adapter.notifyDataSetChanged();
}
}); } @Override
protected void onResume() {
super.onResume();
List<BluetoothDeviceInfo> bluetoothDeviceInfoList = ClientUtil.getInstance().scanDevice();
list.clear();
for (BluetoothDeviceInfo bluetoothDeviceInfo : bluetoothDeviceInfoList) {
list.add(bluetoothDeviceInfo.toString());
adapter.notifyDataSetChanged();
}
} @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Dialog dialog = new Dialog(this);
dialog.setTitle("正在连接..");
dialog.show();
String macAddress = list.get(position).split("\\|")[1];//
ClientUtil.getInstance().connectRemoteDevice(macAddress, new BlueToothConnectCallback() {
@Override
public void connecting(String serverBlueToothAddress) { } @Override
public void connectSuccess(String serverBlueToothAddress) {
dialog.dismiss();
Toast.makeText(DeviceListActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
startActivity(new Intent(DeviceListActivity.this, ClientActivity.class));
} @Override
public void connectFailure(IOException e) {
dialog.dismiss();
Toast.makeText(DeviceListActivity.this, "连接失败..", Toast.LENGTH_SHORT).show();
}
});
} @Override
protected void onDestroy() {
super.onDestroy();
ClientUtil.getInstance().unregisterReceiver(this);
}
}

3.通信页面调用代码(收消息,发消息)

        // 注册收到消息以后的事件
ClientUtil.getInstance().setOnReceivedMessageListener(new ReceivedMessageListener() {
@Override
public void onReceiveMessage(final String messageContent) {
list.add(new MessageEntity(messageContent, true));
listViewAdapterMessage.setData(list);
} @Override
public void onConnectionInterrupt(IOException e) {
btnSend.setEnabled(false);
etMessage.setEnabled(false);
Toast.makeText(ClientActivity.this, "连接中断", Toast.LENGTH_SHORT).show();
startActivity(new Intent(ClientActivity.this, DeviceListActivity.class));
}
});
        // 发送消息
ClientUtil.getInstance().sendMessage(message);
list.add(new MessageEntity(message, false));
listViewAdapterMessage.setData(list);

4.工具类

package de.bvb.bluetoothchat.utils;

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.text.TextUtils; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID; /**
* 客户端(连接端)工具类
*/
public class ClientUtil { public static final String TAG = "BluetoothManagerUtil"; ///////////////////////////////////////////////////////////////////////////
// 单例模式
private ClientUtil() { } public static synchronized ClientUtil getInstance() {
return SingletonHolder.instance;
} private static final class SingletonHolder {
private static ClientUtil instance = new ClientUtil();
}
/////////////////////////////////////////////////////////////////////////// private String serverBlueToothAddress; //连接蓝牙地址
private BluetoothSocket socket = null; // 客户端socket
private BluetoothAdapter bluetoothAdapter; /** 打开蓝牙,注册扫描蓝牙的广播 onCreate()中执行.连接页面调用 */
public void onCreate(Activity activity) {
registerBluetoothScanReceiver(activity);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (null != bluetoothAdapter) { //本地蓝牙存在...
if (!bluetoothAdapter.isEnabled()) { //判断蓝牙是否被打开...
// 发送打开蓝牙的意图,系统会弹出一个提示对话框,打开蓝牙是需要传递intent的...
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//打开本机的蓝牙功能...使用startActivityForResult()方法...这里我们开启的这个Activity是需要它返回执行结果给主Activity的...
activity.startActivityForResult(enableIntent, Activity.RESULT_FIRST_USER); Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 设置蓝牙的可见性,最大值3600秒,默认120秒,0表示永远可见(作为客户端,可见性可以不设置,服务端必须要设置)
displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
//这里只需要开启另一个activity,让其一直显示蓝牙...没必要把信息返回..因此调用startActivity()
activity.startActivity(displayIntent); // 直接打开蓝牙
bluetoothAdapter.enable();//这步才是真正打开蓝牙的部分....
LogUtil.d(TAG, "打开蓝牙成功");
} else {
LogUtil.d(TAG, "蓝牙已经打开了...");
}
} else {
LogUtil.d(TAG, "当前设备没有蓝牙模块");
}
} /** 扫描设备 onResume()中执行.连接页面调用 */
public List<BluetoothDeviceInfo> scanDevice() {
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
LogUtil.e(TAG, "蓝牙状态异常");
return null;
}
List<BluetoothDeviceInfo> bluetoothDeviceInfoList = new ArrayList<>();
if (bluetoothAdapter.isDiscovering()) { // 如果正在处于扫描过程...
/** 停止扫描 */
bluetoothAdapter.cancelDiscovery(); // 取消扫描...
} else {
// 每次扫描前都先判断一下是否存在已经配对过的设备
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
BluetoothDeviceInfo bluetoothDeviceInfo;
for (BluetoothDevice device : pairedDevices) {
bluetoothDeviceInfo = new BluetoothDeviceInfo(device.getName() + "", device.getAddress() + "");
bluetoothDeviceInfoList.add(bluetoothDeviceInfo);
LogUtil.d(TAG, "已经匹配过的设备:" + bluetoothDeviceInfo.toString());
}
} else {
LogUtil.d(TAG, "没有已经配对过的设备");
}
/* 开始搜索 */
bluetoothAdapter.startDiscovery();
}
return bluetoothDeviceInfoList;
} /** 通过Mac地址去尝试连接一个设备.连接页面调用 */
public void connectRemoteDevice(final String serverBlueToothAddress, BlueToothConnectCallback connectInterface) {
this.serverBlueToothAddress = serverBlueToothAddress;
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(serverBlueToothAddress);
ThreadPoolUtil.execute(new ConnectRunnable(device, connectInterface));
} /** 广播反注册.连接页面调用 */
public void unregisterReceiver(Activity activity) {
if (receiver != null && receiver.getAbortBroadcast()) {
activity.unregisterReceiver(receiver);
}
} /** 发送消息,在通信页面使用 */
public void sendMessage(String message) {
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write(message + "\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
} /** 收到消息的监听事件,在通信页面注册这个事件 */
public void setOnReceivedMessageListener(ReceivedMessageListener listener) {
if (listener != null) {
// 可以开启读数据线程
// MainHandler.getInstance().post(new ReadRunnable(listener));
ThreadPoolUtil.execute(new ReadRunnable(listener));
}
} /** 关闭蓝牙,在app退出时调用 */
public void onExit() {
if (bluetoothAdapter != null) {
bluetoothAdapter.cancelDiscovery();
// 关闭蓝牙
bluetoothAdapter.disable();
}
closeCloseable(writer, socket);
} /** 连接线程 */
class ConnectRunnable implements Runnable {
private BluetoothDevice device; // 蓝牙设备
private BlueToothConnectCallback connectInterface; public ConnectRunnable(BluetoothDevice device, BlueToothConnectCallback connectInterface) {
this.device = device;
this.connectInterface = connectInterface;
} @Override
public void run() {
if (null != device) {
try {
if (socket != null) {
closeCloseable(socket);
}
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
// 连接
LogUtil.d(TAG, "正在连接 " + serverBlueToothAddress);
connectInterface.connecting(serverBlueToothAddress);
// Message.obtain(handler, MESSAGE_TYPE_SEND, "请稍候,正在连接服务器: " + serverBlueToothAddress).sendToTarget(); socket.connect();
MainHandler.getInstance().post(new Runnable() {
@Override
public void run() {
connectInterface.connectSuccess(serverBlueToothAddress);
LogUtil.d(TAG, "连接 " + serverBlueToothAddress + " 成功 ");
}
});
// 如果实现了连接,那么服务端和客户端就共享一个RFFCOMM信道...
// Message.obtain(handler, MESSAGE_TYPE_SEND, "已经连接上服务端!可以发送信息").sendToTarget();
// 如果连接成功了...这步就会执行...更新UI界面...否则走catch(IOException e)
// Message.obtain(handler, MESSAGE_ID_REFRESH_UI).sendToTarget(); // 屏蔽点击事件
// listViewMessage.setOnItemClickListener(null);
} catch (final IOException e) {
MainHandler.getInstance().post(new Runnable() {
@Override
public void run() {
connectInterface.connectFailure(e);
LogUtil.d(TAG, "连接" + serverBlueToothAddress + "失败 " + e.getMessage());
}
});
// e.printStackTrace();
}
}
}
} private BufferedWriter writer = null; class ReadRunnable implements Runnable {
private ReceivedMessageListener listener; public ReadRunnable(ReceivedMessageListener listener) {
this.listener = listener;
} public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String content;
while (!TextUtils.isEmpty(content = reader.readLine())) {
final String finalContent = content;
MainHandler.getInstance().post(new Runnable() {
@Override
public void run() {
listener.onReceiveMessage(finalContent);
}
});
// Message.obtain(handler, MESSAGE_TYPE_RECEIVED, content).sendToTarget();
}
} catch (final IOException e) {
MainHandler.getInstance().post(new Runnable() {
@Override
public void run() {
LogUtil.d(TAG, "连接中断 " + e.getMessage());
listener.onConnectionInterrupt(e);
}
});
// 连接断开
// Message.obtain(handler, MESSAGE_ID_DISCONNECT).sendToTarget();
}
closeCloseable(reader);
}
} private BroadcastReceiver registerBluetoothScanReceiver(Activity activity) {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
activity.registerReceiver(receiver, filter);
return receiver;
} public void setOnFoundUnBondDeviceListener(OnFoundUnBondDeviceListener onFoundUnBondDeviceListener) {
this.onFoundUnBondDeviceListener = onFoundUnBondDeviceListener;
} private OnFoundUnBondDeviceListener onFoundUnBondDeviceListener; public interface OnFoundUnBondDeviceListener {
void foundUnBondDevice(BluetoothDevice unBondDevice);
} private void closeCloseable(Closeable... closeable) {
if (null != closeable && closeable.length > 0) {
for (int i = 0; i < closeable.length; i++) {
if (closeable[i] != null) {
try {
closeable[i].close();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeable[i] = null;
}
}
}
}
} /**
* 下面是注册receiver监听,注册广播...说一下为什么要注册广播...
* 因为蓝牙的通信,需要进行设备的搜索,搜索到设备后我们才能够实现连接..如果没有搜索,那还谈什么连接...
* 因此我们需要搜索,搜索的过程中系统会自动发出三个广播...这三个广播为:
* ACTION_DISCOVERY_START:开始搜索...
* ACTION_DISCOVERY_FINISH:搜索结束...
* ACTION_FOUND:正在搜索...一共三个过程...因为我们需要对这三个响应过程进行接收,然后实现一些功能,因此
* 我们需要对广播进行注册...知道广播的人应该都知道,想要对广播进行接收,必须进行注册,否则是接收不到的...
*/
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {//正在搜索过程...
// 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 如果这个设备是不曾配对过的,添加到list列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
if (null != onFoundUnBondDeviceListener) {
LogUtil.d(TAG, "发现没有配对过的设备:" + parseDevice2BluetoothDeviceInfo(device));
onFoundUnBondDeviceListener.foundUnBondDevice(device);
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {//搜索结束后的过程...
LogUtil.d(TAG, "没有发现设备");
}
}
}
}; private String parseDevice2BluetoothDeviceInfo(BluetoothDevice device) {
if (device == null) {
return "device == null";
}
return new BluetoothDeviceInfo(device.getName(), device.getAddress()).toString();
}
}
												

android 蓝牙连接端(客户端)封装的更多相关文章

  1. Android蓝牙连接自动测试工具

    蓝牙连接自动测试工具 1.需求产生 开发不按着需求走都是耍流氓且浪费时间.此工具的需求产生是研发人员在开发产品时涉及到蓝牙驱动和安卓蓝牙两个东西.但是呢,蓝牙不太稳定,那么工作来了.就需要研发人员一边 ...

  2. IOS蓝牙连接 初步简单封装使用

    最近写一个蓝牙项目 初步实现一下蓝牙设备连接交互,后期继续完善.... 1.连接蓝牙相关操作 BlueToothManger.h // // BlueToothManger.h // SmartRob ...

  3. Android蓝牙连接以及数据接收发送

    1.加入权限 <uses-feature android:name="android.hardware.bluetooth_le" android:required=&quo ...

  4. android 蓝牙连接与通讯(Bluetooth)

    最近做了一个小项目,关于蓝牙的一个智能硬件.其中涉及到了蓝牙模块的操作.特记下蓝牙模块的操作过程.只记录下关于蓝牙部分的操作,具体业务逻辑不涉及其中.重点是记录下蓝牙的扫描.链接.通讯. 在使用蓝牙模 ...

  5. TCP Socket服务端客户端(二)

    本文服务端客户端封装代码转自https://blog.csdn.net/zhujunxxxxx/article/details/44258719,并作了简单的修改. 1)服务端 此类主要处理服务端相关 ...

  6. Android一对多蓝牙连接示例APP

    一对多蓝牙连接示例,基于Google BluetoothChat修改,实现一对多聊天(一个服务端.多个客户端),类似聊天室. 主要功能: 客户端的发出的消息所有终端都能收到(由服务端转发) 客户端之间 ...

  7. Android实践 -- Android蓝牙设置连接

    使用Android Bluetooth APIs将设备通过蓝牙连接并通信,设置蓝牙,查找蓝牙设备,配对蓝牙设备 连接并传输数据,以下是Android系统提供的蓝牙相关的类和接口 BluetoothAd ...

  8. Android 蓝牙开发之搜索、配对、连接、通信大全

            蓝牙( Bluetooth®):是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据 交换(使用2.4-2.485GHz的ISM波段的UHF无线电波).蓝牙设备最 ...

  9. Android蓝牙A2DP连接实现

    代码地址如下:http://www.demodashi.com/demo/14624.html 开发环境: 开发工具:Androidstudio 适配机型:honor8(Android6.0), 坚果 ...

随机推荐

  1. arcgis python 使用光标和内存中的要素类将数据加载到要素集 学习:http://zhihu.esrichina.com.cn/article/634

    学习:http://zhihu.esrichina.com.cn/article/634使用光标和内存中的要素类将数据加载到要素集 import arcpy arcpy.env.overwriteOu ...

  2. arcgis python 参数类型和含义

    数据类型 datatype 关键字 描述 地址定位器 DEAddressLocator 用于地理编码的数据集,存储地址属性.关联的索引以及用于定义将地点的非空间描述转换为空间数据这一过程的规则. 地址 ...

  3. (四)OpenCV-Python学习—形态学处理

    通过阈值化分割可以得到二值图,但往往会出现图像中物体形态不完整,变的残缺,可以通过形态学处理,使其变得丰满,或者去除掉多余的像素.常用的形态学处理算法包括:腐蚀,膨胀,开运算,闭运算,形态学梯度,顶帽 ...

  4. netty 聊天室

    https://blog.csdn.net/qq_37372007/article/details/82937584 使用netty实现一个多人聊天室--failed: Error during We ...

  5. linux下安装pm2,pm2: command not found

    1:安装pm2 操作描述: 你要在linux上安装pm2有很多方法,但我是用node的工具npm来完成安装的,所以在安装pm2之前需要先安装node.这里如果不会,就百度一个安装node,这个小事我就 ...

  6. 复习Android布局

    效果如图: 这里没有做逻辑的处理,仅仅是布局的罗列.包括垂直和水平的线性布局,以及一个滚动的view. <?xml version="1.0" encoding=" ...

  7. 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_10-前端显示当前用户-jwt查询接口

    定义接口 在api的项目里面定义.AuthControllerApi里面定义接口 jwtResult,里面就有一个jwt的字段. 实现接口 需要这三步 定义私有方法从cookie中读取访问令牌 参数需 ...

  8. unique_ptr智能指针

    一.VS例子 // Test.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <thread> #includ ...

  9. PAT 甲级 1035 Password (20 分)(简单题)

    1035 Password (20 分)   To prepare for PAT, the judge sometimes has to generate random passwords for ...

  10. fetch jsonp请求接口

    function loadTbbRec() { var fetchJsonp = require('fetch-jsonp'); fetchJsonp(ext.info.tbbRecUrl, { he ...