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. Apache RocketMQ 的过去、现在和未来 原创: DataPipeline DataPipeline数见科技 前天

    Apache RocketMQ 的过去.现在和未来 原创: DataPipeline DataPipeline数见科技 前天

  2. vue 引入公共css文件

    1.在入口js文件main.js中引入,一些公共的样式文件,可以在这里引入. import Vue from 'vue'import App from './App' // 引入App这个组件impo ...

  3. 一台java服务器可以跑多少个线程?

    一台java服务器能跑多少个线程?这个问题来自一次线上报警如下图,超过了我们的配置阈值.   京东自研UMP监控分析 打出jstack文件,通过IBM Thread and Monitor Dump ...

  4. opengl版本

    OpenGL vendor string: IntelOpenGL renderer string: Intel(R) HD Graphics 630OpenGL version string: 4. ...

  5. 123457123457#0#-----com.yuming.ZuiNiuChengYu--前拼后广--最牛成语

    com.yuming.ZuiNiuChengYu--前拼后广--最牛成语

  6. Delphi分割字符串函数Split源码

    function TStringHelper.Split(const Separator: array of string; Count: Integer; Options: TStringSplit ...

  7. Swift学习 (四)

    5.枚举与结构体: 不必给枚举成员提供一个值.如果我们想要为枚举成员提供一个值(raw value),我们可以用字符串,字符,整型或浮点数类型. 1 2 3 4 5 6 7 enum CompassP ...

  8. migrate设置

    migrate配置 进入项目manage所在的目录中执行如下命令,否则会报错:no such table: django_session 进入cmd 输入盘符比如:E: 切换目录 cd E:\prog ...

  9. C#线程 BeginInvoke和EndInvoke使用方法

    一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行.这就需要在同一个进程中开启多个 ...

  10. 【嵌入式硬件Esp32】ESP32学习之在windows下搭建eclipse开发环境

    一.所需工具 由于项目要用ESP32模块进行开发,折腾了下集成开发环境,现将过程记录下来,以便需要的人使用.其中需要的有交叉编译工具,esp-idf示例代码以及C/C++版的eclipse. 交叉编译 ...