Android开发学习秘籍笔记(十九)
吼。花了2天最后做出了一个类似于蓝牙串口助手功能的小程序,事实上也是实习公司的要求---有一个蓝牙无线扫描枪,要求终端能够通过蓝牙连接到该设备,而且蓝牙无线扫描枪扫描二维码或者条形码的时候能够将二维码或者条形码的数据输出到TextView中。
效果:
听效果是不是感觉非常好做。说明下蓝牙扫描器的功能,有2中经常使用的模式--普通模式,SPP模式。 普通模式的话就是相当于蓝牙连接后,扫描器就相当于一个外接的键盘,能够扫码然后将数据输出到EditText(必须获得焦点)。SPP模式则是用于模拟串口通信的,在我看来就相当于开发人员模式。。
。
方案一:在界面代码下手脚,是一种投机取巧的方法。
不是要显示在TextVIew上吗。不是要扫码后仅仅能输出到获得焦点的EditText上吗。那我就在界面代码里设置这两个控件。可是EditText我设置其高度为1dp。除了开发者自己知道这里有个EditText之外。使用者是不知道这里还有个EditText的。
然后你就能够直接将EditText中的内容获取下来,在setText到TextView 中去就能够了。
主要代码就是Edittext的setOnKeyListener里设置就好了。
et.setOnKeyListener(new EditText.OnKeyListener() { @Override publicboolean onKey(View v, int keyCode, KeyEvent event) { tv.setText(et.getText()); returnfalse; } });
操作简单。思路清晰,简单粗暴!可是问题也非常多,万一你一个界面好多个EditText,比方登陆界面。除了你的那个自己知道别人看不到的EditText,还得有两个EditText,一旦某一个获得光标,你的扫描器就失去了作用,还会吓使用者一跳。所以这样的方案不适合用在须要推送的APP上。
方案二:蓝牙传输通信,详细使用到的就是安卓传输的流方式,这样的方式就非常符合要求,就在你要数据传输的时候把你的数据截下来,然后我在做对应的操作。我看了非常多的博客,说真的。这些博客都千篇一律。这里放两篇比較经典的吧。
https://segmentfault.com/a/1190000004899799
http://www.cnblogs.com/wenjiang/p/3200138.html
详细的解释我会在代码里说。光说理论本人菜的抠脚。首先说说布局,超级简单。一个TextView,一个EditText(測试用的) , 一个Button(能够依据自己的须要去掉)。码就不贴了,到时候直接发项目吧!
说说Button的点击事件(能够依据自己的需求进行改动)。点击进入一个Activity显示全部的扫描到的蓝牙设备--DeviceListAcitivty
一:获取扫描到的蓝牙设备
DeviceListActivity里面须要做的事情就是将能扫描到的蓝牙设备显示在ListView中。假设你确定你仅仅要连接一种设备的话而且知道设备的Address的话你大可省略这个操作。这里当学习用。
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener; public class DeviceListActivity extends Activity {
// 调试用
private static final String TAG = "DeviceListActivity";
private static final boolean D = true; // 返回时数据标签
public static String EXTRA_DEVICE_ADDRESS = "设备地址"; // 成员域
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 创建并显示窗体
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); //设置窗体显示模式为窗体方式
setContentView(R.layout.device_list); // 设定默认返回值为取消
setResult(Activity.RESULT_CANCELED); // 设定扫描按键响应
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
}); // 初使化设备存储数组
mPairedDevicesArrayAdapter = new ArrayAdapter<>(this, R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<>(this, R.layout.device_name); // 设置已配队设备列表 ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener); // 设置新查找设备列表
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener); // 注冊接收查找到设备action接收器
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter); // 注冊查找结束action接收器
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter); // 得到本地蓝牙句柄
mBtAdapter = BluetoothAdapter.getDefaultAdapter(); // 得到已配对蓝牙设备列表
//Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); // 加入已配对设备到列表并显示
// 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 = "No devices have been paired";
// mPairedDevicesArrayAdapter.add(noDevices);
// }
} @Override
protected void onDestroy() {
super.onDestroy(); // 关闭服务查找
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
} // 注销action接收器
this.unregisterReceiver(mReceiver);
} public void OnCancel(View v){
finish();
}
/**
* 開始服务和设备查找
*/
private void doDiscovery() {
if (D) Log.d(TAG, "doDiscovery()"); // 在窗体显示查找中信息
setProgressBarIndeterminateVisibility(true);
setTitle("查找设备中..."); // 显示其他设备(未配对设备)列表
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE); // 关闭再进行的服务查找
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
//并又一次開始
mBtAdapter.startDiscovery();
} // 选择设备响应函数
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// 准备连接设备,关闭服务查找
mBtAdapter.cancelDiscovery(); // 得到mac地址
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17); // 设置返回数据
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address); // 设置返回值并结束程序
setResult(Activity.RESULT_OK, intent);
finish();
}
}; // 查找到设备和搜索完毕action监听器
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); // 查找到设备action
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 得到蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 假设是已配对的则略过,已得到显示,其余的在加入到列表中进行显示
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}else{ //加入到已配对设备列表
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// 搜索完毕action
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle("选择要连接的设备");
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = "没有找到新设备";
mNewDevicesArrayAdapter.add(noDevices);
}
// if(mPairedDevicesArrayAdapter.getCount() > 0)
// findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
}
}
}; }
代码贴在上面。详细的代码解释也写在代码上了,事实上我后面是不打算做这部操作的,由于针对仅仅须要连接一个蓝牙设备的程序来说,当我知道了蓝牙设备的Mac地址我就能够直接找到设备,根本不须要查询。但不得不说回来。 当厂家没有给你蓝牙设备的Mac地址的时候。你就不得不做这步操作了!所以推荐的话还是把这步操作给做了的好,详细怎么操作还是得看项目的要求。至于怎样查找蓝牙设备以及蓝牙设备的状态,上面的代码写的非常详细,结合我之前推荐的两篇文章就非常好懂了。
二:传输数据I/O流
但因为它写的代码过于复杂也不是一个框架能够直接利用,所以就没有深究。
https://github.com/hzjerry/BluetoothSppPro。
没办法了。实践是检验真理的唯一标准那就仅仅能開始自己測试了,接下来第二篇文章就发挥了作用,可能我不须要实现ServerSocket服务端的编程,在使用蓝牙串口助手測试的时候,你配对上加连接上就能够直接用了。说明我仅仅须要和它(蓝牙枪)能连接上就好了。
连接的做法过程例如以下:
- 首先你得获取到你须要连接的设备。
(这里就须要你得设备的Mac地址)
- 你须要建立与服务端通信的Socket。看我之前的博客client都是通过IP和port来获得的通信的socket,服务端是通过accept()的方式获取的,
而这里这样的方式被毙了(感觉也不能说毙了。预计是蓝牙枪那边有一个ServerSocket,去accept(),而client有其它的方法拿到通信的Socket。)
- socket.connect()
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address); try{
mBluetoothSocket = mBluetoothDevice.
createRfcommSocketToServiceRecord
(UUID.fromString(MY_UUID));
}catch (IOException e){
Toast.makeText(MainActivity.this, "配对失败,原因是:" + e.getMessage(), Toast.LENGTH_SHORT)
.show();
Log.e("过程", "失败的原因是:" + e.getMessage());
}
//与设备进行连接
try{
mBluetoothSocket.connect();
Toast.makeText(MainActivity.this, "连接"+ mBluetoothDevice.getName()
+ "成功", Toast.LENGTH_SHORT).show();
Log.e("TAGGGAGGAGGHG","连接过程");
} catch (IOException e) {
try{
Toast.makeText(MainActivity.this, "连接失败,原因是:" + e.getMessage(), Toast.LENGTH_SHORT).show();
mBluetoothSocket.close();
mBluetoothSocket = null;
Log.e("连接失败", "连接失败的原因是:" + e.getMessage());
} catch (IOException e1) {
e1.printStackTrace();
}
return;
} //与设备进行传输数据
try{
is = mBluetoothSocket.getInputStream();
}catch (IOException e){
Toast.makeText(MainActivity.this, "接收数据失败", Toast.LENGTH_SHORT).show();
return;
} if(ready_receive == false){
ReadThread.start();
ready_receive = true;
}else {
isReceiving = true;
}
}
});
这一部分就是连接蓝牙设备的操作,本来这些操作我是放到一个线程中去运行的。可是非常不幸的是会报错,然后我就放到UI线程中去了,结果还过了,按道理耗时操作放到UI线程中不是会爆炸的嘛...临时放一放这个问题。然后另一个线程ReadThread
Thread ReadThread = new Thread(){
public void run(){
int num = 0;
byte[] buffer = new byte[1024];
byte[] buffer_new = new byte[1024]; int n = 0;
isReceiving= true;
while(true){
try {
while (is.available() == 0){
while (isReceiving == false){}
}
while(true){
num = is.read(buffer);
n = 0; String s0 = new String(buffer, 0, num);
// fmsg += s0;
for (int i = 0; i < num; i++ ){
if((buffer[i] == 0x0d) && (buffer[i + 1] == 0x0a)){
buffer_new[n] = 0x0a;
i++;
}else{
buffer_new[n] = buffer[i];
}
n++;
}
String s = new String(buffer_new, 0, n);
receive_msg += s;
if (is.available() == 0) break;
}
handler.sendMessage(handler.obtainMessage());
}catch (IOException e){ }
}
}
};
这样就完毕了蓝牙串口助手的部分功能,详细的实例见源代码下载。
源代码下载:
http://download.csdn.net/detail/cuihaoren01/9496677
扫描蓝牙设备,选择须要连接的设备,进行传输。
Android开发学习秘籍笔记(十九)的更多相关文章
- android开发学习笔记000
使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...
- python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法
python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...
- Android开发艺术探索笔记——View(二)
Android开发艺术探索笔记--View(二) View的事件分发机制 学习资料: 1.Understanding Android Input Touch Events System Framewo ...
- Android开发艺术探索笔记—— View(一)
Android开发艺术探索笔记 --View(一) View的基础知识 什么是View View是Android中所有控件的基类.是一种界面层控件的抽象. View的位置参数 参数名 获取方式 含义 ...
- Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式
Android开发艺术探索笔记--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activ ...
- 「Android 开发」入门笔记
「Android 开发」入门笔记(界面编程篇) ------每日摘要------ DAY-1: 学习笔记: Android应用结构分析 界面编程与视图(View)组件 布局管理器 问题整理: Andr ...
- 阿里内部资料:Android开发核心知识笔记共2100页,58万字,完整版开放下载
作为一个3-5年的Android工程师,我们经常会遇到这些瓶颈: 1.技术视野窄长期在小型软件公司,外包公司工作,技术视野被限制的太厉害 2.薪资提升难初中级Android岗位薪资上升空间有限,基本上 ...
- Android开发学习之路-RecyclerView滑动删除和拖动排序
Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...
- Android开发学习路线图
Android开发学习方法: Android是一个比较庞大的体系,从底层的Linux内核到上层的应用层,各部分的内容跨度也比较大.因此,一个好的学习方法对我们学习Android开发很重要. 在此建议, ...
随机推荐
- CSS:超出省略三部曲
overflow:hidden; 超出隐藏 white-space:nowrap; 不让换行,直到<br /> text-overflow:ellipsis; 超出显示省略号... ...
- powerbuilder webbrowser 内嵌浏览器 select下拉框无法使用
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MA ...
- Centos6.5搭建RHCS集群-实现GFS+iSCSI网络共享存储
RHCS集群配置 需要用到的各组件功能:RHCS(Red Hat Cluster Suite):能够提供高可用性.高可靠性.负载均衡.存储共享且经济廉价的集群工具集合.LUCI:是一个基于web的集群 ...
- 部署Redis 成windows服务
Redis是可以安装成windows服务的,开机自启动,命令如下: redis-server --service-install redis.windows.conf 安装完之后,就可看到Redis已 ...
- 说说Linux文件权限那些事儿
文件全部权 显示文件的全部权 更改文件的全部权 文件的权限 改动文件的权限 用符号表示法改动 用数字表示法改动 使用umask指定默认的文件权限 參考文献 首先我们要知道Linux的标准文件权限和安全 ...
- webpack的配置文件entry与output
在webpack.config.js中entry是唯一入口文件 entry也可以是一个数组 如果是一个数组,会将数组里面的文件一起打包到bundle.js entry也可以是一个对象. 如果outpu ...
- 悟道—位IT高管20年的职场心经(读书笔记三)
悟道--一位IT高管20年的职场心经 第三章 世事洞明皆学问 职场就是你的大半个世界 是你一辈子也读不完的一大本书 想明确一个道理. 看明确一件事儿, 你就向成功迈进了一步. 1.1 "四 ...
- ajax乱码解决总结
第一,javascript沿用java的字符处理方式,内部是使用unicode来处理所有字符的,第二,utf-8是每个汉字(unicode字符)用3个字节来存储.第三,用utf-8来send数据是不会 ...
- IFrame和Ajax比較
说到比較,可能我是须要把这连个东西都给大家介绍一下的,可是介于大家都已经有了非常多的理解.我就简单的说了. Ajax: 是指一种创建交互式网页应用的网页开发技术.主要是利用Xm ...
- 打开eclipse中文件所在文件夹
在myeclipse中选中文件后能够打开文件所在文件夹,可是eclipse中没有直接打开文件路径的功能.须要我们自己加入. 选择:Run -> External Tools -> Exte ...