android 蓝牙连接端(客户端)封装

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();
    }
}
				
时间: 2024-12-13 00:20:25

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

Android 蓝牙串口服务客户端开发 尝试

如题,经过三四天的开发尝试已经初步成型,下面是简陋的界面图: 上图是做的蓝牙串口服务的收发界面,主要用于平时的调试之用,由于开发的初衷是为了实现蓝牙对单片机的控制,因此加入了<进入控制/>的按钮选项,下图是控制界(xian)面(tiao) 没办法,没有太多的美学细胞,拖了两个重写的seekbar就作为控制摇杆了... 初次写Android,初次触及Java,水平自然就是无言以对,哈哈,不过为了防止万一以后有需求的升级,博客还是要写的. 1.环境搭建 Android开发者官网上提供了两套集成开发

Android蓝牙连接自动测试工具

蓝牙连接自动测试工具 1.需求产生 开发不按着需求走都是耍流氓且浪费时间.此工具的需求产生是研发人员在开发产品时涉及到蓝牙驱动和安卓蓝牙两个东西.但是呢,蓝牙不太稳定,那么工作来了.就需要研发人员一边开发,一遍测试(用产品的安卓app一直按连接,产品设备重启,安卓app再连接蓝牙,再重启产品设备...........一直循环这个过程),这个过程是无聊且没意义的.我们作为程序员肯定是要偷懒的啊.因此就有了此工具的诞生. 2.功能介绍 1.除首次手动连接所需设备蓝牙外,设备重启后能自动重连 2.连接

android 蓝牙连接与通讯(Bluetooth)

最近做了一个小项目,关于蓝牙的一个智能硬件.其中涉及到了蓝牙模块的操作.特记下蓝牙模块的操作过程.只记录下关于蓝牙部分的操作,具体业务逻辑不涉及其中.重点是记录下蓝牙的扫描.链接.通讯. 在使用蓝牙模块之前要判断设备是否支持蓝牙模块: 1 if (!getPackageManager().hasSystemFeature( 2 PackageManager.FEATURE_BLUETOOTH_LE)) { 3 Toast.makeText(this, R.string.ble_not_suppo

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

        蓝牙( Bluetooth®):是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据 交换(使用2.4-2.485GHz的ISM波段的UHF无线电波).蓝牙设备最多可以同时和7个其它蓝牙设备建立连接,进 行通信,当然并不是每一个蓝牙都可以达到最大值.下面,我们从蓝牙的基本概念开始,一步一步开始了解蓝牙. 基本概念: 安卓平台提供对蓝牙的通讯栈的支持,允许设别和其他的设备进行无线传输数据.应用程序层通过安卓API来调用蓝牙的相关功 能,这些API使程序无线连接

Android开发实践:WIFI连接功能的封装

在上一篇文章<Android开发实践:WIFI扫描功能的封装>介绍了如何利用Andriod的API实现WIFI的扫描,本文则重点讲述一下如何连接WIFI吧,在此,也给出一个封装WIFI连接过程的类,提供简单的接口以供在各个代码工程中复用. 与WIFI扫描类似,WIFI的连接同样是一个耗时的过程,所以需要放到线程中执行,通过回调来通知调用者连接结果.该回调接口的定义如下: public interface WifiConnectListener { public void OnWifiConne

如何实现android蓝牙开发 自动配对连接,并不弹出提示框

如何实现android蓝牙开发 自动配对连接,并不弹出提示框 之前做一个android版的蓝牙,遇到最大的难题就是自动配对. 上网查资料说是用反射createBond()和setPin(),但测试时进行配对还是会出现提示,但配对是成功了 我就开始查找怎么关闭这个蓝牙配对提示框,后面还是伟大的android源码帮助了我. 在源码 BluetoothDevice 类中还有两个隐藏方法 cancelBondProcess()和cancelPairingUserInput() 这两个方法一个是取消配对进

Android pad 连接蓝牙打印机Gprinter---实现蓝牙打印功能

一.概述 最近的一个项目有一个需求,要求通过pad的蓝牙去连接l蓝牙打印机去打印单据,就是点击一个按钮去触发生成单据>>保存到数据库 >>蓝牙打印.首先想要实现蓝牙连接,然后去调用Gprinter的SDK,在这里我使用的是Gprinter SDK2.1的版本,而SDK2.2与SDK2.1 的API有不同的地方,这里就以SDK2.1为例. 二.使用 1.首先要导入jar包.添加依赖,如果没有SDK2.1的版本可以去http://download.csdn.net/download/z

Android从服务端获取json解析显示在客户端上面

Android从服务端获取json解析显示在客户端上面 百度经验:jingyan.baidu.com 首先说一下Json数据的最基本的特点,Json数据是一系列的键值对的集合,和XML数据来比,Json数据的体积更加小,传输效率高,易解析,不过可读性不高; 因为这次要从服务器端得到Json数据,并且通过解析之后把解析后的数据显示在Android客户端中,首先部署服务器端代码(直接使用Jsp/Servlet): 构造的Json数据如下: [{"name":"张三",&

Android应用性能测试(客户端-服务端)平台实现

Android应用性能测试(客户端-服务端)平台实现 东海陈光剑 2014年5月23日 2:01:05 开源项目代码: https://github.com/universsky/EmmageePlus (基于Emmagee) https://github.com/universsky/EmmageePlus/blob/master/src/com/netease/qa/emmagee/service/EmmageeService.java /* * Copyright (c) 2012-201