移动开发作业6——蓝牙通信的简要设计与开发

一、蓝牙通信原理介绍

Android 平台包含蓝牙网络堆栈支持,此支持能让设备以无线方式与其他蓝牙设备交换数据。应用框架提供通过 Android Bluetooth API 访问蓝牙功能的权限。这些 API 允许应用以无线方式连接到其他蓝牙设备,从而实现点到点和多点无线功能。

蓝牙通信和socket通信原理基本上是一致的,下图为Socket通信图:

左为客户端Socket连接的一个流程,右为服务端Socket操作流程。

客户端Socket:
1、创建客户端蓝牙Sokcet
2、创建连接
3、读写数据
4、关闭

服务端Socket:
1、创建服务端蓝牙Socket
2、绑定端口号(蓝牙忽略)
3、创建监听listen(蓝牙忽略, 蓝牙没有此监听,而是通过whlie(true)死循环来一直监听的)
4、通过accept(),如果有客户端连接,会创建一个新的Socket,体现出并发性,可以同时与多个socket通讯)
5、读写数据
6、关闭

二、安卓实现蓝牙通信

1.重要的类和接口

BluetoothAdapter:代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。

BluetoothDevice:代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。

BluetoothSocket:代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。

BluetoothServerSocket:代表一个开放的服务器socket,它监听接受的请求(与TCP ServerSocket类似)。为了连接两台Android设备,一个设备必须使用这个类开启一个服务器socket。当一个远程蓝牙设备开始一个和该设备的连接请求,BluetoothServerSocket将会返回一个已连接的BluetoothSocket,接受该连接。

2.蓝牙权限

首先需要AndroidManifest.xml文件中添加操作蓝牙的权限。

<uses-permissionandroid:name="android.permission.BLUETOOTH" />

允许程序连接到已配对的蓝牙设备。

<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" />

允许程序发现和配对蓝牙设备。

3.客户端

public class ConnectThread extends Thread{
    private static final UUID MY_UUID= UUID.fromString(Constant.CONNECTTION_UUID);
    /** 客户端socket*/
    private final BluetoothSocket mmSoket;
    /** 要连接的设备*/
    private final BluetoothDevice mmDevice;
    private BluetoothAdapter mBluetoothAdapter;
    /** 主线程通信的Handler*/
    private final Handler mHandler;
    /** 发送和接收数据的处理类*/
    private ConnectedThread mConnectedThread;

    public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {
        mmDevice = device;
        mBluetoothAdapter = bluetoothAdapter;
        mHandler = mUIhandler;

        BluetoothSocket tmp = null;
        try {
            // 创建客户端Socket
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            e.printStackTrace();
        }

        mmSoket = tmp;
    }

    @Override
    public void run() {
        super.run();
        // 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)
        mBluetoothAdapter.cancelDiscovery();

        try {
            // 连接服务器
            mmSoket.connect();
        } catch (IOException e) {
            // 连接异常就关闭
            try {
                mmSoket.close();
            } catch (IOException e1) {
            }
            return;
        }

        manageConnectedSocket(mmSoket);
    }

    private void manageConnectedSocket(BluetoothSocket mmSoket) {
        // 通知主线程连接上了服务端socket,更新UI
        mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);
        // 新建一个线程进行通讯,不然会发现线程堵塞
        mConnectedThread = new ConnectedThread(mmSoket,mHandler);
        mConnectedThread.start();
    }

    /**
     * 关闭当前客户端
     */
    public void cancle() {
        try {
            mmSoket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送数据
     * @param data
     */
    public void sendData(byte[] data) {
        if(mConnectedThread != null) {
            mConnectedThread.write(data);
        }
    }
}

4.服务端

public class AcceptThread extends Thread {

    /** 连接的名称*/
    private static final String NAME = "BluetoothClass";
    /** UUID*/
    private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
    /** 服务端蓝牙Sokcet*/
    private final BluetoothServerSocket mmServerSocket;
    private final BluetoothAdapter mBluetoothAdapter;
    /** 线程中通信的更新UI的Handler*/
    private final Handler mHandler;
    /** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/
    private ConnectedThread mConnectedThread;

    public AcceptThread(BluetoothAdapter adapter, Handler handler) throws IOException {
        mBluetoothAdapter = adapter;
        this.mHandler = handler;

        // 获取服务端蓝牙socket
        mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
    }

    @Override
    public void run() {
        super.run();
        // 连接的客户端soacket
        BluetoothSocket socket = null;

        // 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环
        while (true){
            // 通知主线程更新UI,客户端开始监听
            mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);
            try {
                // 获取连接的客户端socket
                socket =  mmServerSocket.accept();
            } catch (IOException e) {
                // 通知主线程更新UI, 获取异常
                mHandler.sendEmptyMessage(Constant.MSG_ERROR);
                e.printStackTrace();
                // 服务端退出一直监听线程
                break;
            }

            if(socket != null) {
                // 管理连接的客户端socket
                manageConnectSocket(socket);

                // 这里应该是手动断开,案例应该是只保证连接一个客户端,所以连接完以后,关闭了服务端socket
//                try {
//                    mmServerSocket.close();
//                    mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
            }
        }
    }

    /**
     * 管理连接的客户端socket
     * @param socket
     */
    private void manageConnectSocket(BluetoothSocket socket) {
        // 只支持同时处理一个连接
        // mConnectedThread不为空,踢掉之前的客户端
        if(mConnectedThread != null) {
            mConnectedThread.cancle();
        }

        // 主线程更新UI,连接到了一个客户端
        mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);
        // 新建一个线程,处理客户端发来的数据
        mConnectedThread = new ConnectedThread(socket, mHandler);
        mConnectedThread.start();
    }

    /**
     * 断开服务端,结束监听
     */
    public void cancle() {
        try {
            mmServerSocket.close();
            mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送数据
     * @param data
     */
    public void sendData(byte[] data){
        if(mConnectedThread != null) {
            mConnectedThread.write(data);
        }
    }
}

5.共同通讯处理类

public class ConnectedThread extends Thread{
    /** 当前连接的客户端BluetoothSocket*/
    private final BluetoothSocket mmSokcet;
    /** 读取数据流*/
    private final InputStream mmInputStream;
    /** 发送数据流*/
    private final OutputStream mmOutputStream;
    /** 与主线程通信Handler*/
    private Handler mHandler;
    private String TAG = "ConnectedThread";

    public ConnectedThread(BluetoothSocket socket,Handler handler) {
        mmSokcet = socket;
        mHandler = handler;

        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        mmInputStream = tmpIn;
        mmOutputStream = tmpOut;
    }

    @Override
    public void run() {
        super.run();
        byte[] buffer = new byte[1024];

        while (true) {
            try {
                // 读取数据
                int bytes = mmInputStream.read(buffer);

                if(bytes > 0) {
                    String data = new String(buffer,0,bytes,"utf-8");
                    // 把数据发送到主线程, 此处还可以用广播
                    Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);
                    mHandler.sendMessage(message);
                }

                Log.d(TAG, "messge size :" + bytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 踢掉当前客户端
    public void cancle() {
        try {
            mmSokcet.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 服务端发送数据
     * @param data
     */
    public void write(byte[] data) {
        try {
            mmOutputStream.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6.BlueToothController蓝牙控制类

public class BlueToothController {
    private BluetoothAdapter mAapter;

    public BlueToothController() {
        mAapter = BluetoothAdapter.getDefaultAdapter();
    }

    public BluetoothAdapter getAdapter() {
        return mAapter;
    }
    /**
     * 打开蓝牙
     * @param activity
     * @param requestCode
     */
    public void turnOnBlueTooth(Activity activity, int requestCode) {
        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        activity.startActivityForResult(intent, requestCode);
//        mAdapter.enable();
    }

    /**
     * 打开蓝牙可见性
     * @param context
     */
    public void enableVisibly(Context context) {
        Intent discoverableIntent = new
                Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
        context.startActivity(discoverableIntent);
    }

    /**
     * 查找设备
     */
    public void findDevice() {
        assert (mAapter != null);
        mAapter.startDiscovery();
    }

    /**
     * 获取绑定设备
     * @return
     */
    public List<BluetoothDevice> getBondedDeviceList() {
        return new ArrayList<>(mAapter.getBondedDevices());
    }
}

蓝牙设备adaptor代码DeviceAdapter

public abstract class DeviceAdapter extends BaseAdapter {
    private Context mContext;
    private List<BluetoothDevice> mDate;

    public DeviceAdapter(List<BluetoothDevice> Date, Context context){
        mDate = Date;
        mContext = context;

    }
    @Override
    public int getCount() {
        return mDate.size();
    }

    @Override
    public Object getItem(int position) {
        return mDate.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if(convertView==null){
            viewHolder = new ViewHolder();
            viewHolder.textView1 = (TextView)convertView.findViewById(R.id.textView1);
            viewHolder.textView2 = (TextView)convertView.findViewById(R.id.textView2);
            convertView.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder) convertView.getTag();
        }
        //获取蓝牙设备
        BluetoothDevice bluetoothDevice = (BluetoothDevice) getItem(position);
        viewHolder.textView1.setText("Name="+bluetoothDevice.getName());
        viewHolder.textView2.setText("Address"+bluetoothDevice.getAddress());
        return convertView;
    }

    public class ViewHolder{
        public TextView textView1;
        public  TextView textView2;

    }
    public void refresh(List<BluetoothDevice> data){
        mDate = data;
        notifyDataSetChanged();
    }
}

7.蓝牙device接受广播Receiver

private BroadcastReceiver mReceiverBluetoothStatus = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context,Intent intent) {
            String action = intent.getAction();
            if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
                // 开始搜索        ——接收广播
                Log.d(TAG,"开始搜索");
                mList.clear();
                mAdapter.refresh(mList);

            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                // 查找到设备完成   —— 接收广播
                Log.d(TAG,"查找到设备完成");

            } else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 搜索到设备       —— 接收广播
                Log.d(TAG,"搜索到设备");
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                mList.add(device);
                mAdapter.refresh(mList);


            } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
                // 当自己设备设置蓝牙可见时或者不可见时 —— 接收广播
                int scanMode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,0);
                // 可见时
                if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
                    Log.d(TAG,"设备可见监听");
                } else {
                    Log.d(TAG,"设备不可见监听");
                }

            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                // 绑定状态改变回调
                BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (remoteDevice == null) {
                    Log.d(TAG,"没有绑定设备");
                    return;
                }

                int status = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,0);
                if (status == BluetoothDevice.BOND_BONDED) {
                    Log.d(TAG,"绑定设备完成: " + remoteDevice.getName());
                } else if (status == BluetoothDevice.BOND_BONDING) {
                    Log.d(TAG,"绑定设备中: " + remoteDevice.getName());
                } else if (status == BluetoothDevice.BOND_NONE) {
                    Log.d(TAG,"取消绑定: ");
                }
            }
        }
    };

 三、结果展示

四、源码地址

https://github.com/zljdgit/MyApplicationBluetooth.git

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Socket是指设备之间通过无线连接建立的通信通道。通过Socket,设备可以进行数据的传输和交换,实现互相之间的通信功能。 Socket是一种面向连接的通信方式,即在进行通信之前,需要先建立两个设备之间的连接。这种连接方式可以确保通信的稳定性和可靠性。Socket使用一对端口来标识通信的两个设备,一个端口用于接收数据,另一个端口用于发送数据。 相比传统的有线通信方式,Socket的优势在于无线连接,不需要使用数据线或者网络连接,更加便捷。Socket广泛用于各种设备之间的通信,如手机与耳机、键盘、打印机等的连接,以及智能家居设备之间的互联互通。 Socket的实现依赖于协议栈和相应的开发工具。开发人员可以利用Socket实现设备之间的数据传输和交互,例如发送命令、接收数据等。同时,开发人员还可以通过Socket实现设备之间的远程控制和管理,以及实现更加复杂的功能。 总之,Socket是一种无线通信方式,通过建立连接实现设备之间的数据传输和交互。它在各种设备之间的通信中起到了重要的作用,为用户提供了更加便捷和灵活的通信方式。 ### 回答2: socket是一种用于通信的软件接口。它建立了设备之间的通信连接,允许数据在设备之间传输。socket对于通信的应用程序尤为重要,它提供了一种可靠的通信方式。 通过socket,设备可以建立远程通信连接,例如手机与耳机之间的通信。这种通信方式是无线的,因此非常方便。socket可以处理多种类型的数据,例如音频、视频、文件等。 socket的使用需要一些特定的协议和设置,以确保通信的正确性和速度。通常,当设备之间建立连接时,它们会自动协商和选择适当的协议和设置。 socket还有一些特性,例如安全性和能效性。socket可以使用加密等安全措施,以防止数据泄漏或非法访问。此外,socket还可以通过调整传输速率和功耗来提高能效性,以适应不同类型的应用需求。 总之,socket是一种重要的软件接口,为设备之间的通信提供了便捷而可靠的方式。它广泛应用于手机、平板电脑、耳机、音箱等各种设备中,为用户提供了更好的使用体验。 ### 回答3: Socket是一种无线通信协议,用于在设备之间建立连接和实现数据传输。它是技术中的一种通信方式,可以用于连接各种设备,如手机、电脑、音频设备等。 Socket的工作原理是通过建立连接,将数据以流的形式传输。通过Socket,可以实现设备之间的数据传输和通信,比如发送文件、播放音乐、远程控制等。Socket提供了一种简单、方便、低功耗的方式,使得设备之间的互联变得更加容易。 Socket具有以下特点: 1. 无线传输:Socket不需要物理连接线,通过无线技术进行数据传输。 2. 简单易用:Socket使用简单,只需建立连接并发送数据即可实现通信。 3. 低功耗:Socket采用低功耗技术,节省设备电量,延长电池使用寿命。 4. 安全可靠:Socket支持加密和验证机制,确保通信的安全性和可靠性。 5. 多设备连接:Socket可以同时连接多个设备,实现设备间的并行通信。 总之,Socket是一种便捷实用的无线通信方式,适用于各种设备之间的数据传输和通信。它的应用范围广泛,如耳机、车载、智能家居等领域,为设备间的互联提供了一种简单方便的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值