`

2013.09.05——— android 蓝牙聊天室之官方例子

阅读更多
2013.09.05——— android 蓝牙聊天室之官方例子

蓝牙开发的大致流程:

1、蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH" />


2、认设备是否支持蓝牙
/**
         * 确认设备是否支持蓝牙
         * 如果getDefaultAdapter()返回null,则这个设备不支持蓝牙
         */
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        //手机不支持蓝牙
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }


3、确定蓝牙能够使用
/**
         * 确定蓝牙能够使用。
         * 通过isEnabled()来检查蓝牙当前是否可用。
         * 如果这个方法返回false,则蓝牙不能够使用。这个时候 就请求蓝牙使用,通过intent来请求
		 * 在onActivityResult()里面判断
         */
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        }

会打开一个对话框中显示请求使用蓝牙权限。如果响应"Yes",这个进程完成(或失败)后你的应用将能够使用蓝牙,选择no,就结束应用

case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
            	//请求蓝牙成功,这个时候 蓝也可用
                setupChat();
            } else {
                // User did not enable Bluetooth or an error occurred
            	//请求蓝牙失败,退出应用
                Log.d(TAG, "BT not enabled");
                Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                finish();
            }



4、最为服务器端,你必须让其他设备能够看到你,才能跟你建立连接
//设置自己可以被其他设备搜索到
    private void ensureDiscoverable() {
        if(D) Log.d(TAG, "ensure discoverable");
        if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }

5、找已经匹配的设备
在搜索设备前,查询配对设备看需要的设备是否已经是已经存在是很值得的,可以调用getBondedDevices()来做到,该函数会返回一个描述配对设备BluetoothDevice的结果集
//查找已经匹配的设备
        Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();

        // If there are paired devices, add each one to the ArrayAdapter
        if (pairedDevices.size() > 0) {
            findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
            for (BluetoothDevice device : pairedDevices) {
                mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
            }
        } else {
            String noDevices = getResources().getText(R.string.none_paired).toString();
            mPairedDevicesArrayAdapter.add(noDevices);
        }

6、扫描设备
/**
     * Start device discover with the BluetoothAdapter
     */
    private void doDiscovery() {
        if (D) Log.d(TAG, "doDiscovery()");

        // Indicate scanning in the title
        setProgressBarIndeterminateVisibility(true);
        setTitle(R.string.scanning);

        // Turn on sub-title for new devices
        findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);

        // If we're already discovering, stop it
        //如果正在搜索 就先停止
        if (mBtAdapter.isDiscovering()) {
            mBtAdapter.cancelDiscovery();
        }

        // Request discover from BluetoothAdapter
        //搜索设备 用BroadcastReceiver接受BluetoothDevice.ACTION_FOUND
        mBtAdapter.startDiscovery();
    }


要开始搜索设备,只需简单的调用startDiscovery() 。该函数时异步的,调用后立即返回,返回值表示搜索是否成功开始。可以再BroadcastReceiver里面监听结果

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // If it's already paired, skip it, because it's been listed already
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
                }
            // When discovery is finished, change the Activity title
            }
    };


7、作为客户端连接
扫描出来的列表,单击任意一个item,得到这个设备的mac地址和name
// The on-click listener for all devices in the ListViews
    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
        public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
            // Cancel discovery because it's costly and we're about to connect
        	//停止搜索
            mBtAdapter.cancelDiscovery();

            // Get the device MAC address, which is the last 17 chars in the View
            String info = ((TextView) v).getText().toString();
            String address = info.substring(info.length() - 17);

            // Create the result Intent and include the MAC address
            Intent intent = new Intent();
            intent.putExtra(EXTRA_DEVICE_ADDRESS, address);

            // Set result and finish this Activity
            setResult(Activity.RESULT_OK, intent);
            finish();
        }
    };

根据mac地址 得到远端BluetoothDevice
       
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);


然后 根据device得到BluetoothSocket,并建立连接
private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private String mSocketType;

        public ConnectThread(BluetoothDevice device, boolean secure) {
            mmDevice = device;
            BluetoothSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";

            // Get a BluetoothSocket for a connection with the
            // given BluetoothDevice
            //来生成一个BluetoothSocket对象
            //这个uuid必须服务器和客户端是同一个
            try {
                if (secure) {
                    tmp = device.createRfcommSocketToServiceRecord(
                            MY_UUID_SECURE);
                } else {
                    tmp = device.createInsecureRfcommSocketToServiceRecord(
                            MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
            //设置当前线程名字
            setName("ConnectThread" + mSocketType);

            // Always cancel discovery because it will slow down a connection
            //因为扫描设备 很浪费资源 停止扫描
            mAdapter.cancelDiscovery();

            // Make a connection to the BluetoothSocket
            //用connect()完成连接
            //系统会在远程设备上完成一个SDP查找来匹配UUID。
            //如果查找成功并且远程设备接受连接,就共享RFCOMM信道,connect()会返回。
            //这也是一个阻塞的调用,不管连接失败还是超时(12秒)都会抛出异常。
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                mmSocket.connect();
            } catch (IOException e) {
                // Close the socket
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() " + mSocketType +
                            " socket during connection failure", e2);
                }
                connectionFailed();
                return;
            }

            // Reset the ConnectThread because we're done
            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            // Start the connected thread
            //启动连接成功 可以通信的线程
            connected(mmSocket, mmDevice, mSocketType);
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
            }
        }
    }


8、作为服务器端建立连接

private class AcceptThread extends Thread {
        // The local server socket
        private final BluetoothServerSocket mmServerSocket;
        private String mSocketType;

        public AcceptThread(boolean secure) {
            BluetoothServerSocket tmp = null;
            mSocketType = secure ? "Secure":"Insecure";

            // Create a new listening server socket
            //通过调用listenUsingRfcommWithServiceRecord(String, UUID)得到一个BluetoothServerSocket对象
            try {
                if (secure) {
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
                        MY_UUID_SECURE);
                } else {
                    tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
                            NAME_INSECURE, MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
            }
            mmServerSocket = tmp;
        }

        public void run() {
            if (D) Log.d(TAG, "Socket Type: " + mSocketType +
                    "BEGIN mAcceptThread" + this);
            setName("AcceptThread" + mSocketType);

            BluetoothSocket socket = null;

            // Listen to the server socket if we're not connected
            while (mState != STATE_CONNECTED) {
                try {
                    // This is a blocking call and will only return on a
                    // successful connection or an exception
                	//通过调用accept()来侦听连接请求。
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                    Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
                    break;
                }

                // If a connection was accepted
                if (socket != null) {
                    synchronized (BluetoothChatService.this) {
                        switch (mState) {
                        case STATE_LISTEN:
                        case STATE_CONNECTING:
                            // Situation normal. Start the connected thread.
                            connected(socket, socket.getRemoteDevice(),
                                    mSocketType);
                            break;
                        case STATE_NONE:
                        case STATE_CONNECTED:
                            // Either not ready or already connected. Terminate new socket.
                            try {
                                socket.close();
                            } catch (IOException e) {
                                Log.e(TAG, "Could not close unwanted socket", e);
                            }
                            break;
                        }
                    }
                }
            }
            if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);

        }

        public void cancel() {
            if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
            try {
                mmServerSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
            }
        }
    }


9、与远端设备通信

//处理与远端的通信
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket, String socketType) {
            Log.d(TAG, "create ConnectedThread: " + socketType);
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the BluetoothSocket input and output streams
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);

                    // Send the obtained bytes to the UI Activity
                    mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    // Start the service over to restart listening mode
                    BluetoothChatService.this.start();
                    break;
                }
            }
        }

        /**
         * Write to the connected OutStream.
         * @param buffer  The bytes to write
         */
        //发送信息给远端
        public void write(byte[] buffer) {
            try {
                mmOutStream.write(buffer);

                // Share the sent message back to the UI Activity
                mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }



附件是官网的例子,稍微加了点注释
分享到:
评论
1 楼 u014408122 2015-07-31  

相关推荐

    2024-2030全球及中国控制膨胀合金箔行业研究及十五五规划分析报告.docx

    2024-2030全球及中国控制膨胀合金箔行业研究及十五五规划分析报告

    通信历年真题选择题汇总1.(DOC).doc

    通信历年真题选择题汇总1.(DOC).doc

    电子通信设计资料电子万年历设计与制作论文资料

    电子通信设计资料电子万年历设计与制作论文资料提取方式是百度网盘分享地址

    JSP-SSM健身俱乐部客户关系管理系统可升级SpringBoot源码.7z

    前台框架基于Bootstrap这一HTML5响应式框架,能够自适应不同终端设备的屏幕大小,为用户提供良好的浏览体验。开发环境兼容myEclipse、Eclipse、Idea等多种工具,配合mysql数据库,实现数据的存储与管理。后台则采用SSM(SpringMVC + Spring + Mybatis)框架,保证系统的稳定与高效运行。 系统主要包括会员信息管理、员工信息管理、设备信息管理以及退出模块。会员信息管理模块详细记录了会员的基本信息、健身目标、消费记录以及健身习惯等,同时设有会员投诉管理模块,用于收集和处理会员的意见与建议。员工信息管理模块则涵盖了员工的基本信息、工资发放情况等,帮助俱乐部进行人事管理。设备信息管理模块则负责建立器械档案,跟踪维修情况,并合理安排器械摆放位置,以延长器械使用寿命。 数据库设计方面,会员表记录了会员的各项基本信息,包括姓名、性别、职业等;部门表与员工表则分别用于记录俱乐部的组织机构和员工信息;会员消费表记录了会员的消费详情;员工工资表则用于记录员工的工资发放情况;留言表用于收集会员的留言及回复;设备类别表与设备表则详细记录了会所内器械的分类与具

    2024-2030全球及中国超级殷钢 32-5行业研究及十五五规划分析报告.docx

    2024-2030全球及中国超级殷钢 32-5行业研究及十五五规划分析报告

    2023年贴剂行业竞争格局与市场机会.pptx

    行业分析报告

    linux nginx免安装文件

    linux环境不能上网,用这个文件可以实现nginx免安装

    按点击量排序-基于内容的课程推荐网站的设计与实现(SSM+html).zip

    “按点击量排序-基于内容的课程推荐网站的设计与实现(SSM+html)”是一个基于内容推荐概念的在线学习平台,旨在为用户提供个性化的课程推荐体验。系统的核心功能包括用户注册登录、课程浏览搜索、个性化推荐和热门课程按点击量排序展示。在技术架构方面,该系统采用SSM框架作为后端开发技术,包括Spring、Spring MVC和MyBatis,用于处理业务逻辑和数据持久化。前端界面则采用HTML设计实现,展示课程信息和用户交互界面。这样的技术选择不仅提供了稳定的后端支持,还保证了良好的前端用户体验。通过SSM框架以及HTML的结合,该课程推荐网站在功能性和性能方面表现优异。SSM框架提供了高效的业务处理和数据交互,HTML则赋予网站美观友好的用户界面,使用户能够轻松使用课程推荐功能。热门课程的点击量排序功能提高了用户浏览体验,使用户更快速地找到感兴趣的课程,从而提升整体用户满意度和学习效率。

    OSP项目施工组织方案.docx

    行业分析报告

    小型婚礼(可动态添加祝福语)程序文件jquery

    1:场景一主要有两个功能,第一个是控制左边图片,第二个是让右边文字逐一显示。 2:场景二功能简单一点,只控制左边人物出现,紧接着是文字显示。 3:场景三功能控制图片弹跳显示,我用for循环控制弹跳距离。 4:场景四控制图片从顶部往下滑落,停留1秒然后滑向右侧直至消失。 5:场景五慢慢显现,可点击进入婚礼。 6:场景六显现停留1.6秒,然后以碎片的形式向外散开。 7:场景七祝福贴纸随机排布,并且可拖动祝福贴纸。 8:添加祝福语中,需填写祝福语,否则不让提交。可提交的祝福语便随机散布在祝福墙中,可实现随意拖动功能,

    AI相关领域论文+英文中文+论文攻读

    AI论文体系建设是指建立一个完善的AI领域的论文研究框架和体系,以促进学术交流和知识积累。这一体系包括但不限于以下几个方面: 1. **研究主题界定**:明确AI领域的研究主题和范围,包括机器学习、深度学习、自然语言处理、计算机视觉等方向。 2. **文献综述**:对AI领域相关研究文献进行综述和分类,总结研究现状和发展趋势,为后续研究提供参考。 3. **研究方法论**:探讨AI研究的方法论,包括实验设计、数据采集、模型构建等方面的方法和技巧。 4. **实验验证**:强调实验验证在AI研究中的重要性,提倡开放数据和代码,以促进研究结果的可复现性和可验证性。 5. **学术交流**:倡导学术交流和合作,包括参加学术会议、发表论文、组织研讨会等方式,促进学术成果的传播和交流。 6. **学术评价**:建立科学的学术评价体系,包括SCI、EI等学术期刊和会议的评价标准,以及学术成果的评价指标和方法。 通过建设完善的AI论文体系,可以促进AI领域的学术研究和技术创新,推动人工智能技术的发展和应用。

    2024年硬件嵌入式系统咨询行业分析报告.pptx

    行业分析报告

    智慧医院大健康全院信息化建设解决方案.pptx

    围绕着医疗安全与医疗机构管理精细化目标,借鉴HIMSS评级标准、JCI评审、等级医院评审标准规范,基于统一的技术平台架构下的医教研人财物六位一体的信息化管理解决方案,实现医疗卫生机构医务、护理、人力资源、科研、教学、医患关系、设备与物资供应链等日常管理运营信息化。 利用移动互联网技术构建专业的分享服务平台,以为会员提供相关知识、专家在线服务、法律咨询服务,并为医生、医疗机构和健康管理会所提供宣传服务等众多增值服务。 4 大目标: 高效诊疗、智慧医疗、精细管理、信息便民; 1 卡通: 一张诊疗卡。 1 个平台: 一个医院信息集成平台; 6 大应用: 医疗管理、临床信息、运营管理、移动物联、医疗协作、对外服务。

    基于PHP的轻量级MVC框架设计源码

    本项目是基于PHP的轻量级MVC框架设计源码,包含56个文件,其中主要包含50个php源代码文件。系统采用了PHP编程语言,实现了基于PHP7+的轻量级MVC框架。该框架适用于博客系统、新闻管理系统、企业官网和Api系统等多种应用场景,是这些系统的最佳选择。项目结构清晰,代码可读性强,易于理解和维护。

    飞行器机动飞行质点弹道仿真-侧向和纵向-龙格库塔/欧拉法

    本Matlab程序的主要功能是实现飞行器的侧向和纵向的机动,通过设计横向和纵向的控制指令实现。系统状态(微分方程)的解算提供了两种方式,龙格库塔法和欧拉法。 主程序main_cexiang:实现飞行器的侧向机动; 主程序main_zongxiang:实现飞行器的纵向机动。

    基于ssm+vue学生学籍管理系统源码数据库文档.zip

    基于ssm+vue学生学籍管理系统源码数据库文档.zip

    mybatis-plus-generator-3.5.3.jar

    mybatis-plus-generato.jar 包,各个版本,免费下载。 mybatis-plus 代码生成器生成代码框架。各个版本,免费下载。 下载不了,关注我,评论区联系我。

    java-springboot+vue“智慧食堂”设计与实现源码(源代码+说明文档资料)

    springboot+vue“智慧食堂”设计与实现 系统主要包括首页,个人中心,用户管理,菜品分类管理,菜品信息管理,留言板管理,系统管理,订单管理等功能。 项目关键技术 开发工具:IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7+ 框架:ssm、Springboot 前端:Vue、ElementUI 关键技术:springboot、SSM、vue、MYSQL、MAVEN 数据库工具:Navicat、SQLyog

    基于ssm+vue孩童收养信息管理系统源码数据库文档.zip

    基于ssm+vue孩童收养信息管理系统源码数据库文档.zip

    概率论与潮流统计学在时尚产业的应用(文档加Matlab源码)

    本文深入探讨了概率论在时尚产业中的应用,分析了如何利用统计学原理来预测和引导时尚潮流。内容涵盖了数据收集、市场趋势分析、消费者行为研究以及如何通过概率模型来优化设计和营销策略。文章适合时尚产业的设计师、市场分析师、品牌经理以及对时尚趋势感兴趣的学者和学生。无论是在设计新款服饰、制定市场推广计划,还是在学术研究中,本文都能提供有价值的见解和方法。 关键词 时尚产业

Global site tag (gtag.js) - Google Analytics