Android蓝牙开发---站在前辈的肩膀上唠嗑

描述一段背景:前年我找工作时,总碰到一个问题。

面试官问:“你会蓝牙开发吗?”。

我说:“不会”。

面试官答:“那,很抱歉。我们商量了一下,觉得你不适合这个岗位。”

于是我就走了,心里想:“就应为一个蓝牙通讯技术不会,就把我给cut了,这面试官好有想象力。”

我一个同学,都没做过编程,我半年时间都带到android开发道上了。我仅仅蓝牙没做过,研究蓝牙无非就是三两天的时间,难吗?

于是,我周末窝在家里,查阅了大量资料,实践和总结,研究透了蓝牙技术。

有些同学可能会说,蓝牙简单,无非就是扫描设备,配对,和socket通讯。

没错,是这些,但是还有很多坑你不知道,还有很多奇葩代码。废话少说,一起分享吧。

想使用蓝牙呢,首先得看手机是否支持,有些低配手机,可能就没有内置蓝牙模块。当然,一般都会有,我们可以得到唯一的蓝牙适配器,进行其他操作。

bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

然后,我们可做n多的事情。不要着急,后面会附上我的项目源码,大牛见笑了。

/**
     * 开启蓝牙
     *
     * @param activity 上下文
     * @return 是否开启成功
     */
    public static boolean openBluetooth(Activity activity) {
        //确认开启蓝牙
        if (!getInstance().isEnabled()) {
            //=默认120秒==============================================================
            //使蓝牙设备可见,方便配对
            //Intent in = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            //in.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            //activity.startActivityForResult(in,Activity.RESULT_OK);
            //=1=============================================================
            //请求用户开启,需要提示
            //Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            //startActivityForResult(intent, RESULT_FIRST_USER);
            //=2=============================================================
            //程序直接开启,不经过提示
            getInstance().enable();
        }
        //T.showLong(context, "已经开启蓝牙");
        return getInstance().isEnabled();
    }

    //关闭蓝牙
    public static boolean closeBluetooth() {
        return getInstance().disable();
    }

    /**
     * 扫描已经配对的设备
     *
     * @return
     */
    public static ArrayList<BluetoothDevice> scanPairs() {
        ArrayList<BluetoothDevice> list = null;
        Set<BluetoothDevice> deviceSet = getInstance().getBondedDevices();
        if (deviceSet.size() > 0) {
            //存在已经配对过的蓝牙设备
            list = new ArrayList<>();
            list.addAll(deviceSet);
        }
        return list;
    }

    //开始扫描
    public static void scan() {
        getInstance().startDiscovery();
    }

    //取消扫描
    public static void cancelScan() {
        if (getInstance().isDiscovering())
            getInstance().cancelDiscovery();

    }

    //蓝牙配对
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean createBond(BluetoothDevice device) {
        return bond(device, "createBond");
        /*if (device.createBond()) {
            return device.setPairingConfirmation(true);
        }
        return false;*/
    }

    //解除配对
    public static boolean removeBond(BluetoothDevice device) {
        return bond(device, "removeBond");
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private static boolean bond(BluetoothDevice device, String methodName) {
        Boolean returnValue = false;
        if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
            try {
                device.setPairingConfirmation(false);
                cancelPairingUserInput(device);
                Method removeBondMethod = BluetoothDevice.class.getMethod(methodName);
                returnValue = (Boolean) removeBondMethod.invoke(device);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return returnValue;
    }

    //取消配对
    public static boolean cancelBondProcess(BluetoothDevice device) {
        try {
            Method cancelBondMethod = BluetoothDevice.class.getMethod("cancelBondProcess");
            Boolean returnValue = (Boolean) cancelBondMethod.invoke(device);
            return returnValue.booleanValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //取消用户输入
    public static boolean cancelPairingUserInput(BluetoothDevice device) {
        try {
            Method cancelPairingUserInputMethod = BluetoothDevice.class.getMethod("cancelPairingUserInput");
            Boolean returnValue = (Boolean) cancelPairingUserInputMethod.invoke(device);
            return returnValue.booleanValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

通过上面这段代码,应道知道了吧,获取到适配器后,可以得到当前手机已经配对的设备。同时可以开启扫描(这个时间大概是12秒,异步的),扫描到设备和扫描完成系统会发广播。故广播接收代码:

//注册蓝牙接收广播
        if (!hasRegister) {
            hasRegister = true;
            //扫描结束广播
            IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
            //找到设备广播
            filter.addAction(BluetoothDevice.ACTION_FOUND);
            filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
            filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
            registerReceiver(mMyReceiver, filter);
        }
private class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                //搜索到新设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                //搜索没有配过对的蓝牙设备
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    mListData.add(device);
                    dataAdapter.refreshData(mListData);
                } else {
                    T.showLong(TwoActivity.this, device.getName() + '\n' + device.getAddress() + " > 已发现");
                }
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {   //搜索结束
                if (mListData.size() == 0) {
                    T.showLong(TwoActivity.this, "没有发现任何蓝牙设备");
                }
                progressDialog.dismiss();
                scan.setText("重新扫描");
            } else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
                if (TwoActivity.this.position != -1) {
                    final BluetoothDevice device = mListData.get(TwoActivity.this.position);
                    com.dk.bluetooth.tools.T.showLong(TwoActivity.this, device + "  配对成功");
                    EventBus.getDefault().post(new com.dk.bluetooth.tools.MyEvent());
                }
            }
        }
    }

以上都不是重点,核心在线程通讯。首先得了解socket,java有这个,蓝牙里面也有,是BluetoothServerSocket和BluetoothSocket两个,一个是服务器端的,一个是客户端的。不了解的朋友建议先去百度java socket用法,超级简单。

通讯需要建立信道,BluetoothServerSocket需要先启动,监听当前设备上的某UUID位置上的设备(阻塞到在此处),就跟windows的端口意思是一样的。然后BluetoothSocket再启动,根据对方的mac地址和对方监听的UUID位置,启动连接(也阻塞了),直到连上服务器了,就返回。服务器也一样,直到有人来连接了,就返回。都会返回一个BluetoothSocket,然后从这个socket里面获取input和output流。服务器端了input流是客户端的output流,另外一半也一样。剩下的收发消息就是流的读写了,简单吧。

下面贴出我的代码,应为服务器端和客户端启动的方法不一样,我分成了两个线程,由于读写的功能一样,我就共用了一套读写线程。根据这个思路看我的代码。

/**
     * 初始化及启动蓝牙socket
     *
     * @param handler         UI消息传递对象
     * @param securityType    连接的安全模式
     * @param serverOrClient  客户端或服务端
     * @param bluetoothDevice 服务器端设备
     */
    public BluetoothChatService(Handler handler, SecurityType securityType, ServerOrClient serverOrClient,
                                BluetoothDevice bluetoothDevice) {
        if (securityType != null)
            this.mSecurityType = securityType;
        if (serverOrClient != null)
            this.mServerOrClient = serverOrClient;
        if (bluetoothDevice != null)
            this.mBluetoothDevice = bluetoothDevice;
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mHandler = handler;
        start();
    }

    /**
     * 多线程同步修改状态标识
     *
     * @param state
     */
    private synchronized void setState(int state) {
        mState = state;
        mHandler.obtainMessage(MESSAGE_TOAST_STATE_CHANGE, state, -1, null).sendToTarget();
    }

    /**
     * 多线程同步读取状态标识
     */
    public synchronized int getState() {
        return mState;
    }

    /**
     * 启动服务
     */
    public void start() {
        start(null, null, null);
    }

    /**
     * 启动服务
     *
     * @param securityType    连接的安全模式
     * @param serverOrClient  客户端或服务端
     * @param bluetoothDevice 服务器端设备
     */
    public void start(SecurityType securityType, ServerOrClient serverOrClient, BluetoothDevice bluetoothDevice) {
        if (securityType != null)
            this.mSecurityType = securityType;
        if (this.mSecurityType == null) {
            if (DEBUG)
                Log.e(TAG, "mSecurityType cannot be null");
            mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mSecurityType cannot be null").sendToTarget();
            return;
        }
        if (serverOrClient != null)
            this.mServerOrClient = serverOrClient;
        if (this.mServerOrClient == null) {
            if (DEBUG)
                Log.e(TAG, "mServerOrClient cannot be null");
            mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mServerOrClient cannot be null").sendToTarget();
            return;
        }
        if (bluetoothDevice != null)
            this.mBluetoothDevice = bluetoothDevice;
        if (this.mBluetoothDevice == null) {
            if (DEBUG)
                Log.e(TAG, "mBluetoothDevice cannot be null");
            mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mBluetoothDevice cannot be null").sendToTarget();
            return;
        }
        if (mState == STATE_NONE) {
            stop();
            if (this.mServerOrClient == ServerOrClient.SERVER) {
                if (mServerConnectThread == null) {
                    mServerConnectThread = new ServerConnectThread(this.mSecurityType);
                    mServerConnectThread.start();
                }
            } else if (this.mServerOrClient == ServerOrClient.CLIENT) {
                if (mClientConnectThread == null) {
                    mClientConnectThread = new ClientConnectThread(this.mSecurityType);
                    mClientConnectThread.start();
                }
            }
            setState(STATE_LISTEN);
        }
    }

    /**
     * 停止服务
     */
    public synchronized void stop() {
        try {
            if (mReadWriteThread != null) {
                mReadWriteThread.cancel();
                mReadWriteThread = null;
            }
            if (mServerConnectThread != null) {
                mServerConnectThread.cancel();
                mServerConnectThread = null;
            }
            if (mClientConnectThread != null) {
                mClientConnectThread.cancel();
                mClientConnectThread = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (DEBUG)
                Log.e(TAG, "BluetoothChatService -> stop() -> :failed " + e.getMessage());
            mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "BluetoothChatService -> stop() -> :failed").sendToTarget();
            mReadWriteThread = null;
            mServerConnectThread = null;
            mClientConnectThread = null;
        } finally {
            setState(STATE_NONE);
            System.gc();
        }
    }

    /**
     * 发送消息
     *
     * @param out 数据参数
     */
    public void write(String out) {
        if (TextUtils.isEmpty(out)) {
            if (DEBUG)
                Log.e(TAG, "please write something now");
            mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "BluetoothChatService -> write() -> :failed").sendToTarget();
            return;
        }
        ReadWriteThread r;
        synchronized (this) {
            if (mState != STATE_CONNECTED)
                return;
            r = mReadWriteThread;
        }
        r.write(out);
    }

    /**
     * 服务器端连接线程
     */
    @SuppressLint("NewApi")
    private class ServerConnectThread extends Thread {
        private BluetoothServerSocket mmServerSocket;
        private BluetoothSocket mmSocket = null;

        public ServerConnectThread(SecurityType securityType) {
            setName("ServerConnectionThread:" + securityType.getValue());
            BluetoothServerSocket tmp = null;
            try {
                if (securityType == SecurityType.SECURE) {
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(SecurityType.SECURE.getValue(), MY_UUID_SECURE);
                } else if (securityType == SecurityType.INSECURE) {
                    tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(SecurityType.INSECURE.getValue(),
                            MY_UUID_INSECURE);
                }
                if (tmp != null)
                    mmServerSocket = tmp;
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ServerConnectThread -> ServerConnectThread() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> ServerConnectThread() -> :failed").sendToTarget();
                mmServerSocket = null;
                BluetoothChatService.this.stop();
            }
        }

        public void run() {
            try {
                // 正在连接
                setState(STATE_CONNECTING);
                //accept() 阻塞式的方法,群聊时,需要循环accept接收客户端
                mmSocket = mmServerSocket.accept();
                connected(mmSocket);
            } catch (Exception e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ServerConnectThread -> run() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> run() -> :failed").sendToTarget();
                BluetoothChatService.this.stop();
            }
        }

        public void cancel() {
            try {
                if (mmSocket != null) {
                    mmSocket.close();
                    mmSocket = null;
                }
                if (mmServerSocket != null) {
                    mmServerSocket.close();
                    mmServerSocket = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ServerConnectThread -> cancel() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> cancel() -> :failed").sendToTarget();
                mmSocket = null;
                mmServerSocket = null;
                BluetoothChatService.this.stop();
            }
        }
    }

    // 客户端连接线程
    private class ClientConnectThread extends Thread {
        private BluetoothSocket mmSocket;

        public ClientConnectThread(SecurityType securityType) {
            setName("ClientConnectThread:" + securityType.getValue());
            BluetoothSocket tmp = null;
            try {
                if (securityType == SecurityType.SECURE) {
                    tmp = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
                    //Method m = mBluetoothDevice.getClass().getMethod("createRfcommSocket", int.class);
                    //tmp = (BluetoothSocket) m.invoke(mBluetoothDevice, 1);
                } else if (securityType == SecurityType.INSECURE) {
                    tmp = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE);
                    //Method m = mBluetoothDevice.getClass().getMethod("createRfcommSocket", int.class);
                    //tmp = (BluetoothSocket) m.invoke(mBluetoothDevice, 1);
                }
                if (tmp != null)
                    mmSocket = tmp;
            } catch (Exception e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ClientConnectThread -> ClientConnectThread() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> ClientConnectThread() -> :failed").sendToTarget();
                mmSocket = null;
                BluetoothChatService.this.stop();
            }
        }

        public void run() {
            try {
                setState(STATE_CONNECTING);
                mmSocket.connect();
                connected(mmSocket);
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ClientConnectThread -> run() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> run() -> :failed").sendToTarget();
                BluetoothChatService.this.stop();
            }
        }

        public void cancel() {
            try {
                if (mmSocket != null && mmSocket.isConnected()) {
                    mmSocket.close();
                }
                mmSocket = null;
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ClientConnectThread -> cancel() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> cancel() -> :failed").sendToTarget();
                mmSocket = null;
                BluetoothChatService.this.stop();
            }
        }
    }

    /**
     * 以获取socket,建立数据流线程
     *
     * @param socket
     */
    private synchronized void connected(BluetoothSocket socket) {
        if (mReadWriteThread != null) {
            mReadWriteThread.cancel();
            mReadWriteThread = null;
        }
        mReadWriteThread = new ReadWriteThread(socket);
        mReadWriteThread.start();
    }

    /**
     * 连接成功线程,可进行读写操作
     */
    private class ReadWriteThread extends Thread {
        private BluetoothSocket mmSocket;
        private DataInputStream mmInStream;
        private DataOutputStream mmOutStream;
        private boolean isRunning = true;

        public ReadWriteThread(BluetoothSocket socket) {
            mmSocket = socket;
            try {
                mmInStream = new DataInputStream(mmSocket.getInputStream());
                mmOutStream = new DataOutputStream(mmSocket.getOutputStream());
                // 连接建立成功
                setState(STATE_CONNECTED);
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ReadWriteThread -> ReadWriteThread() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> ReadWriteThread() -> :failed").sendToTarget();
                mmOutStream = null;
                mmInStream = null;
                BluetoothChatService.this.stop();
            }
        }

        public void run() {
            byte[] buffer = new byte[1024];
            int len;
            while (isRunning) {
                try {
                    //readUTF(),read(buffer) 都是阻塞式的方法
                    //如果这儿用readUTF,那么写的地方得用writeUTF。对应
                    String receive_str = mmInStream.readUTF();
                    if (!TextUtils.isEmpty(receive_str))
                        mHandler.obtainMessage(MESSAGE_RECEIVE, -1, -1, receive_str).sendToTarget();
//                    len = mmInStream.read(buffer);
//                    if(len > 0){
//                        String receive_str = new String(buffer,0,len);
//                        if (!TextUtils.isEmpty(receive_str))
//                            mHandler.obtainMessage(MESSAGE_RECEIVE, -1, -1, receive_str).sendToTarget();
//                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    if (DEBUG)
                        Log.e(TAG, "ReadWriteThread -> run() -> :failed " + e.getMessage());
                    mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> run() -> :failed").sendToTarget();
                    BluetoothChatService.this.stop();
                }
            }
        }

        public void write(String str) {
            try {
                mmOutStream.writeUTF(str);
                mmOutStream.flush();
                mHandler.obtainMessage(MESSAGE_TOAST_SEND, -1, -1, str).sendToTarget();
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ReadWriteThread -> write() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> write() -> :failed").sendToTarget();
                BluetoothChatService.this.stop();
            }
        }

        public void cancel() {
            try {
                isRunning = false;
                if (mmInStream != null) {
                    mmInStream.close();
                    mmInStream = null;
                }
                if (mmOutStream != null) {
                    mmOutStream.close();
                    mmOutStream = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
                if (DEBUG)
                    Log.e(TAG, "ReadWriteThread -> cancel() -> :failed " + e.getMessage());
                mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> cancel() -> :failed").sendToTarget();
                mmInStream = null;
                mmOutStream = null;
                BluetoothChatService.this.stop();
            }
        }
    }

sorry,不要蛋疼,不要骂娘,代码确实有这么多。以上代码使我在前辈的基础上优化改进了的。可以作为一个公共的蓝牙通讯工具类使用。

下面贴出我的项目功能,是一个聊天程序,只能单聊。我不明太网上有很多demo声称能群聊怎么实现的,据目前分析,服务器端和客户端的管道流是一一对应的,不是广播模式。如果能群聊,会在服务器端创建一个输入输出流管理的集合吧,服务器端没收到一条消息,在=再循环输出流集合,往各个客户端都发送消息。这样一来,我上面的这段代码不够用了。懒得改,故没有做群聊。

先贴图:

程序中,socket的连接方式有安全连接和不安全连接,我一直没有搞懂区别

在两个手机都连接了wifi的情况加,再使用我这种蓝牙通讯方式通讯时,io流连接上后会自动断开,很奇怪。查资料说蓝牙通讯的波段频率与路由器的冲突了。没辙,故在启动程序的时候关闭了wifi,下下策,望大家提供思路。

最后附上源码。有遗漏和错误,望大家指点。

源码下载

时间: 2024-10-07 07:36:40

Android蓝牙开发---站在前辈的肩膀上唠嗑的相关文章

站在巨人的肩膀上学习Android开发

我们知道,一开始最好的学习方法是模仿,尤其是模仿巨人.那说到Android开发的模仿自然就是分析并研究主流程序的布局.实现方法,进而提升自己的技术. 第一招----逆向工程 要分析"巨人"们的软件,自然免不了逆向工程,即将APK程序转化为我们可以看的懂得源码.这个google官方已经帮我们做好了工具,apktool就是一款很好的逆向工具. 下载地址为:http://pan.baidu.com/s/1kTqRhaR 我们以分析微信为例来说明这个工具的使用: 你只需执行如下命令,即完成了反

Android系统研究资料收集---站在前人的肩膀上

Android系统研究资料收集---站在前人的肩膀上 针对Android系统研究任务,收集高价值资料在本页更新 AuthBlog:秋城https://www.cnblogs.com/houser0323 目录 1 官方网站 2 书籍 3 一些开发者的博客 1 官方网站 Android Open Source Project Android开源项目的官网,关于AOSP的官方资料都在这里,内容丰富全面偏概念性,适合用来总览Android aosp项目的全貌.跟踪了解版本特性 中文官网:https:/

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

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

Android蓝牙开发的一些经验

转载请注明来自:http://blog.csdn.net/icyfox_bupt/article/details/25487125 最近在实验室做项目,使用了Android的蓝牙开发,这里面有好多坑..所以还是希望能记下来这些东西和大家分享,不要再走我的老路了. 先说一下背景,我是开发手机与带蓝牙的智能设备(蓝牙血压计.血糖仪.手环等)设备对接的APP.也就是说,在设备端没有什么可以操作的,手机负责发起数据传输. 蓝牙连接,不需要配对 由于被曾经使用蓝牙的思路所误导,一直以为使用蓝牙是必须一个配

Android蓝牙开发

Android蓝牙开发 近期做蓝牙小车,须要Android端来控制小车的运动.以此文记录开发过程. 使用HC-06无线蓝牙串口透传模块.对于其它的蓝牙设备本文相同适用. 蓝牙开发的流程: 获取本地蓝牙适配器    -->     打开蓝牙    -->    搜索设备  -->   连接设备  -->   发送信息 首先为了避免以往我们先写入蓝牙权限: <uses-permission android:name="android.permission.BLUETOO

Android蓝牙开发入门

目录: 1. 蓝牙简史,现状 2. 蓝牙的应用场景 3. 蓝牙相关概念 4. Android蓝牙开发 1. 蓝牙简史: 蓝牙( Bluetooth)是一种无线技术标准,可以实现短距离(通常是几米范围之内)的无线通信.蓝牙技术始于1994年,迄今已经发展了超过20年.本质上它和其它几种射频通信技术类似,比如手机移动通信,近场通信技术(NFC),都是通过电磁波来实现不同设备的信息交换.区别在于无线电波的频率和发射功率不一样,从而传输距离也不一样. 2. 蓝牙的应用场景: l 移动电话和免提设备之间的

Android蓝牙开发,报BluetoothAdapter﹕ Can&#39;t create handler inside thread that has not called Looper.prepare

这个错误翻译的意思是:不能在没有Looper.prepare的线程里面创建handler. 起初我很疑惑,我根本没有用到工作线程,也没有创建handler.报错的代码如下: // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final Blu

年薪百万的程序员都是站在巨人的肩膀上开发

要想成为一名软件开发者需要学习各种专业知识.技术与框架.比如算法.数据结构.编程语言.流行框架等.但是要想成为更加出色的软件开发者,你要学习的就不仅仅是专业上的知识了. 标题过于浮夸,希望大家谅解,但本篇是满满的干货.今天我想分享一点关于软件开发者如何改进职业技能从而变得更擅长于自身工作的技巧.这里要谈的主题是通用性的,并没有针对任何特定的技术栈.其实这里要谈的大部分甚至都不是针对 IT 的.这些都是如何形成个人特质,跟同事.客户改进协作,以及拓展作为软件开发者职业生涯的一般性建议. 端到端理解

小游戏“跳一跳”——站在巨人的肩膀上,用技术为自己助力

在更新最新版微信之后,聊天列表下拉会出现一个崭新的模块,其中就有新推出的"跳一跳"小游戏.而在我几经努力奋斗到266分的时候,已经有技术大牛占据1999的高地... 抱着试一试的心态和蠢蠢欲动的好奇心... 实现了程序助力玩游戏... 具体代码来自gitHub的python大牛... 感兴趣的同学可以和我一起站在巨人的肩膀上... 另外说一点, 如果以后还想玩"跳一跳"的话... 不建议你接着往下看... 因为当你有了捷径... 整个游戏瞬间变得索然无味... 如果