zoukankan      html  css  js  c++  java
  • 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>
    View Code

    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);
        }
    }
    View Code

    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 + "
    ");
                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();
        }
    }
    
    
  • 相关阅读:
    linux下将可执行程序进行打包
    多节点OpenMPI集群的搭建和使用
    快排
    git 出现:warning: LF will be replaced by CRLF in
    String 根据 第一个逗号去掉逗好后面的内容
    SpringBoot项目中想去掉数据库查询到的数组双括号
    mybatis-plus多条件 or 的使用
    从linux上的docker持久化mysql数据恢复到本地mysql数据库
    @Repository和@Mapper
    JavaScript动画实例:爆裂的粒子
  • 原文地址:https://www.cnblogs.com/Westfalen/p/6933788.html
Copyright © 2011-2022 走看看