Android 基于蓝牙的方向控制器
最近开发了一个蓝牙控制器App,用手机远程控制小球的运动。
包含了一些基础知识:多线程使用,页面UI数据更新,按钮事件,选择项功能,蓝牙功能(蓝牙打开,蓝牙搜索,蓝牙连接,蓝牙命令发送,蓝牙命令接收)。
开发环境为:Android Studio+Java,蓝牙模块HC-06(自发自收模式)。
实现代码
主Activity代码:
- package com.example.cxk.lightballcontroller;
- 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.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.ArrayAdapter;
- import android.widget.Button;
- import android.widget.CompoundButton;
- import android.widget.EditText;
- import android.widget.Spinner;
- import android.widget.Switch;
- import android.widget.TextView;
- import android.widget.Toast;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.lang.ref.WeakReference;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Set;
- import java.util.UUID;
- public class MainActivity extends Activity {
- private Switch bluetoothSwitch;
- private Button bluetoothSearch;
- private Spinner bluetoothList;
- private Button bluetoothConnect;
- private TextView recvData;
- private EditText sendData;
- private Button bluetoothSend;
- private Button upSend;
- private Button leftSend;
- private Button downSend;
- private Button rightSend;
- private BluetoothAdapter bluetoothAdapter;
- private List<String> list = new ArrayList<String>();
- private ArrayAdapter<String> adapter;
- private String strMacAddress;
- private boolean booleanConnect = false;
- private ConnectedThread connectedThread;
- private MyHandler myHandler = new MyHandler(this);
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- bluetoothSwitch = (Switch) findViewById(R.id.swtch);
- bluetoothSearch = (Button) findViewById(R.id.search);
- bluetoothList = (Spinner) findViewById(R.id.list);
- bluetoothConnect = (Button) findViewById(R.id.connect);
- recvData = (TextView) findViewById(R.id.recvdata);
- sendData = (EditText) findViewById(R.id.senddata);
- bluetoothSend = (Button) findViewById(R.id.send);
- upSend = (Button)findViewById(R.id.BtnUp);
- leftSend = (Button)findViewById(R.id.BtnLeft);
- downSend = (Button)findViewById(R.id.BtnDown);
- rightSend = (Button)findViewById(R.id.BtnRight);
- bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if(bluetoothAdapter == null){
- //表明此手机不支持蓝牙
- Toast.makeText(MainActivity.this, "未发现蓝牙设备", Toast.LENGTH_SHORT).show();
- return;
- }
- if (bluetoothAdapter.isEnabled()) {
- bluetoothSwitch.setChecked(true);
- }
- adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- bluetoothList.setAdapter(adapter);
- bluetoothList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
- strMacAddress = adapter.getItem(i);
- adapterView.setVisibility(View.VISIBLE);
- }
- @Override
- public void onNothingSelected(AdapterView<?> adapterView) {
- }
- });
- bluetoothSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- if (b) {
- if (!bluetoothAdapter.isEnabled()) { //蓝牙未开启,则开启蓝牙
- Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivity(enableIntent);
- } else {
- Toast.makeText(MainActivity.this, "蓝牙已开启", Toast.LENGTH_SHORT).show();
- }
- } else {
- bluetoothAdapter.disable();
- Toast.makeText(MainActivity.this, "蓝牙已关闭", Toast.LENGTH_SHORT).show();
- }
- }
- });
- bluetoothSearch.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (bluetoothAdapter == null) {
- Toast.makeText(MainActivity.this, "未发现蓝牙设备", Toast.LENGTH_SHORT).show();
- return;
- } else if (!bluetoothAdapter.isEnabled()) {
- Toast.makeText(MainActivity.this, "蓝牙设备未开启", Toast.LENGTH_SHORT).show();
- }
- Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
- if (pairedDevices.size() > 0) {
- for (BluetoothDevice device : pairedDevices) {
- adapter.remove(device.getAddress());
- adapter.add(device.getAddress());
- }
- } else {
- //注册,当一个设备被发现时调用mReceive
- IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
- registerReceiver(mReceiver, filter);
- }
- }
- });
- bluetoothConnect.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (strMacAddress == null) {
- Toast.makeText(MainActivity.this, "请先搜索设备", Toast.LENGTH_SHORT).show();
- } else {
- BluetoothDevice device = bluetoothAdapter.getRemoteDevice(strMacAddress);
- ConnectThread connectThread = new ConnectThread(device);
- connectThread.start();
- }
- }
- });
- bluetoothSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (booleanConnect == false) {
- Toast.makeText(MainActivity.this, "请先连接设备", Toast.LENGTH_SHORT).show();
- } else {
- String strSendData = new String(sendData.getText().toString());
- connectedThread.write(strSendData.getBytes());
- sendData.setText("");
- }
- }
- });
- upSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (booleanConnect == false) {
- Toast.makeText(MainActivity.this, "请先连接设备", Toast.LENGTH_SHORT).show();
- } else {
- String str = "ONA\n";
- String strSendData = new String(str);
- connectedThread.write(strSendData.getBytes());
- sendData.setText("");
- }
- }
- });
- downSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (booleanConnect == false) {
- Toast.makeText(MainActivity.this, "请先连接设备", Toast.LENGTH_SHORT).show();
- } else {
- String str = "ONB\n";
- String strSendData = new String(str);
- connectedThread.write(strSendData.getBytes());
- sendData.setText("");
- }
- }
- });
- leftSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (booleanConnect == false) {
- Toast.makeText(MainActivity.this, "请先连接设备", Toast.LENGTH_SHORT).show();
- } else {
- String str = "ONC\n";
- String strSendData = new String(str);
- connectedThread.write(strSendData.getBytes());
- sendData.setText("");
- }
- }
- });
- rightSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (booleanConnect == false) {
- Toast.makeText(MainActivity.this, "请先连接设备", Toast.LENGTH_SHORT).show();
- } else {
- String str = "OND\n";
- String strSendData = new String(str);
- connectedThread.write(strSendData.getBytes());
- sendData.setText("");
- }
- }
- });
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private static class MyHandler extends Handler {
- WeakReference<MainActivity> mActivity;
- MyHandler(MainActivity activity) {
- mActivity = new WeakReference<MainActivity>(activity);
- }
- @Override
- public void handleMessage(Message msg) {
- MainActivity theActivity = mActivity.get();
- theActivity.recvData.append(msg.obj.toString());
- }
- }
- @Override
- protected void onDestroy() {
- if (connectedThread != null) {
- connectedThread.cancel();
- }
- super.onDestroy();
- }
- private BroadcastReceiver mReceiver = new 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) {
- adapter.add(device.getAddress());
- }
- }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //搜索结束
- if (adapter.getCount() == 0) {
- Toast.makeText(MainActivity.this, "没有搜索到设备", Toast.LENGTH_SHORT).show();
- }
- }
- }
- };
- private class ConnectThread extends Thread{
- private BluetoothSocket mmsocket;
- private BluetoothDevice mmdevice;
- public ConnectThread(BluetoothDevice device){
- mmdevice = device;
- BluetoothSocket tmp = null;
- try {
- tmp = mmdevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
- } catch (IOException e) {
- }
- mmsocket = tmp;
- }
- public void run(){
- bluetoothAdapter.cancelDiscovery(); //取消设备查找
- try {
- mmsocket.connect();
- } catch (IOException e) {
- try {
- mmsocket.close();
- } catch (IOException e1) {
- }
- //连接失败
- return;
- }
- booleanConnect = true;
- //新建一个数据交换线程
- connectedThread = new ConnectedThread(mmsocket);
- connectedThread.start();
- }
- public void cancel() {
- try {
- mmsocket.close();
- } catch (IOException e) {
- }
- }
- }
- private class ConnectedThread extends Thread{
- private BluetoothSocket mmsocket;
- private InputStream inStream;
- private OutputStream outStream;
- public ConnectedThread(BluetoothSocket socket){
- mmsocket = socket;
- try {
- //获得输入输出流
- inStream = mmsocket.getInputStream();
- outStream = mmsocket.getOutputStream();
- } catch (IOException e) {
- }
- }
- public void run(){
- byte[] buff = new byte[1];
- int len = 0;
- //读数据需不断监听,写不需要
- while(true){
- try {
- len = inStream.read(buff);
- //把读取到的数据发送给UI进行显示
- String strBuffer = new String(buff);
- Message toMain = myHandler.obtainMessage();
- toMain.obj = strBuffer;
- myHandler.sendMessage(toMain);
- } catch (IOException e) {
- break;
- }
- }
- }
- public void write(byte[] buffer) {
- try {
- outStream.write(buffer);
- } catch (IOException e) {
- }
- }
- public void cancel() {
- try {
- mmsocket.close();
- } catch (IOException e) {
- }
- }
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_settings) {
- super.finish();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- }
界面代码:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
- tools:context=".MainActivity"
- android:weightSum="1">
- <Switch
- android:id="@+id/swtch"
- android:textOn="@string/open"
- android:textOff="@string/close"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_gravity="center_horizontal" />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:weightSum="1">
- <Button
- android:id="@+id/search"
- android:text="@string/search"
- android:layout_width="wrap_content"
- android:layout_height="37dp"
- android:background="#ff9ed7ff" />
- <Spinner
- android:id="@+id/list"
- android:layout_width="162dp"
- android:layout_height="48dp"
- android:layout_weight="1.17" />
- <Button
- android:id="@+id/connect"
- android:text="@string/connect"
- android:layout_width="93dp"
- android:layout_height="38dp"
- android:background="#ff9ed7ff" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- </LinearLayout>
- <RelativeLayout
- android:layout_width="350dp"
- android:layout_height="112dp"
- android:layout_gravity="center_horizontal"
- android:id="@+id/DirectionPanel">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/up"
- android:id="@+id/BtnUp"
- android:layout_above="@+id/BtnRight"
- android:layout_centerHorizontal="true"
- android:background="#ffd0e2ff" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/left"
- android:id="@+id/BtnLeft"
- android:layout_alignParentBottom="true"
- android:layout_toLeftOf="@+id/BtnUp"
- android:background="#ffd0e2ff" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/right"
- android:id="@+id/BtnRight"
- android:layout_alignTop="@+id/BtnLeft"
- android:layout_toRightOf="@+id/BtnUp"
- android:background="#ffd0e2ff" />
- </RelativeLayout>
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/down"
- android:id="@+id/BtnDown"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_gravity="center_horizontal"
- android:background="#ffd0e2ff" />
- <EditText
- android:id="@+id/senddata"
- android:layout_width="356dp"
- android:layout_height="wrap_content"
- android:layout_weight="0.18" />
- <Button
- android:id="@+id/send"
- android:text="@string/send"
- android:layout_width="84dp"
- android:layout_height="33dp"
- android:background="#ff9ed7ff"
- android:layout_gravity="right" />
- <TextView
- android:text="@string/recv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="66dp"
- android:id="@+id/scrollView"
- android:layout_weight="0.82"
- android:background="#ffc8c8c8">
- <TextView
- android:id="@+id/recvdata"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0.99"
- android:background="#ffc8c8c8" />
- </ScrollView>
- </LinearLayout>
实现的效果
实现工程代码:蓝牙控制器
参考资料:
http://www.pudn.com/downloads691/sourcecode/comm/android/detail2784484.html
Android 基于蓝牙的方向控制器的更多相关文章
- 【源代码】基于Android和蓝牙的单片机温度採集系统
如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 STC89C52单片机通过HC-06蓝牙模块与Android手机通信实例- 基于And ...
- Android Studio 蓝牙开发实例——基于Android 6.0
因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...
- 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程
原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ UART HCI_UART H4 HCI L2CAP ...
- Android 串口蓝牙通信开发Java版本
Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...
- Android 低功耗蓝牙BLE 开发注意事项
基本概念和问题 1.蓝牙设计范式? 当手机通过扫描低功耗蓝牙设备并连接上后,手机与蓝牙设备构成了客户端-服务端架构.手机通过连接蓝牙设备,可以读取蓝牙设备上的信息.手机就是客户端,蓝牙设备是服务端. ...
- 【腾讯优测干货分享】Android 相机预览方向及其适配探索
本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/583ba1df25d735cd2797004d 由于Android系统的开放策略 ...
- ubuntu16.04连接android手机蓝牙共享网络热点
最近的想要用android手机蓝牙共享wifi网络给ubuntu16.04系统用,查了好多资料,发现网上很少有有用的.自己实践后分享如下. 第一步:手机与电脑配对: 该步骤比较简单,网 ...
- Android BLE 蓝牙编程(一)
最近在研究这个,等我有时间来写吧! 终于在端午节给自己放个假,现在就来说说关于android蓝牙ble的 最近的学习成果吧!! 需要材料(写个简单教程吧--关于小米手环的哦!嘿嘿) Android 手 ...
- Android基于XMPP的即时通讯3-表情发送
这篇博文主要讲表情发送的一些东西. 参考:Android基于XMPP的即时通讯1-基本对话 1.准备好资源文件 采用的是emoji的表情,我打包好了,下载地址:http://files.cnblogs ...
随机推荐
- 16 - 文件操作-StringIO-BytesIO
目录 1 文件操作 1.1 open函数介绍 1.2 打开操作 1.2.1 mode模式 1.2.2 文件指针 1.2.3 缓冲区 1.2.4 encoding编码 1.2.5 其他参数 1.3 读写 ...
- 《深入理解Java虚拟机》笔记--第十三章、线程安全与锁优化
先保证并发的正确性,然后在此基础上来实现高效. 线程安全: 当多个线程访问一个对象时,如果不考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操 ...
- MYSQL三种安装方式--二进制包安装
1. 把二进制包下载到/usr/local/src下 2. 如果是tar.gz包,则使用tar zxvf 进行解压 如果是tar包,则可以使用tar xvf 进行解压 3. $ mv mysql-5. ...
- 一个设置为display:none;的div,在用.height()方法获取不到它的高,获取到的高度为0.
<div style="width:100px;height:100px;background:red;visibility:hidden"></div>/ ...
- day01作业
Java技术按照用途不同分为三大版本,分别是JavaSE.JavaEE和JavaMeJava虚拟机就是一个虚拟的用于执行字节码文件的计算机.它是Java最核心的技术,是Java跨平台的基础.DOS命令 ...
- 三十分钟理解计算图上的微积分:Backpropagation,反向微分
神经网络的训练算法,目前基本上是以Backpropagation (BP) 反向传播为主(加上一些变化),NN的训练是在1986年被提出,但实际上,BP 已经在不同领域中被重复发明了数十次了(参见 G ...
- 深度揭秘阿里移动端高性能动态化方案Weex
2016年Qcon大会首日,阿里巴巴资深总监.淘宝移动平台.阿里百川负责人庄卓然宣布移动端高性能动态化方案Weex即时内测,并将于6月开源.此消息一出,群情汹涌,在座的程序猿.攻城狮们纷纷拿起手机扫码 ...
- LoadRunner 使用虚拟IP测试流程
LoadRunner 使用虚拟IP测试流程 LoadRunner 使用IP欺骗的原因 . 当某个IP的访问过于频繁,或者访问量过大是,服务器会拒绝访问请求,这时候通过IP欺骗可以增加访问频率和访问量, ...
- 使用自己的域名解析 cnblogs 博客
使用自己的域名解析 cnblogs 博客(博客园) 1.实现原理 用户访问 -> 阿里云解析 -> github page 跳转 -> 真实的博客地址 2.创建 github pag ...
- C++运算符重载规则
运算符重载时要遵循以下规则: ( 1 ) 除了类属关系运算符 " . " .成员指针运算符 " .* " .作用域运算符 " :: " . ...