您的位置:首页 > 理论基础 > 计算机网络

android蓝牙和网络通信项目总结(一)

2015-09-02 18:27 603 查看

android蓝牙和网络通信项目总结(一)

最近在家没网络,用手机开热点做了一个蓝牙和网络通信的小项目,在这里总结一下。主要是和硬件通信的一个app啦,从同学那里拿个蓝牙模块做的测试,觉得挺有趣的,整个项目做下来,因为感觉有很多东西需要总结的,所以分几篇进行总结。

一,扫描二维码

这个app的其中一个功能是扫描二维码,然后获得设备信息,添加设备,这样以后app就可以直接连接设备了,对于二维码的操作,我使用的是比较出名的zxing框架。在github上很容易找到可以使用的例子。首先我是先和做硬件的同学商量好怎么定二维码信息的格式的,商量好就好说了,打开myeclipse,写个生成二维码的工具,然后生成二维码。然后使用手机扫描二维码,获得数据,保存到手机。主要代码如下:
Intent intent = new Intent();
				intent.putExtra("result", rawResult.getText());
				setResult(RESULT_OK, intent);
				rw = rawResult.getText().split("&@");
				SmartDevice smartDevice = new SmartDevice();
				smartDevice.setName(rw[0]);
				smartDevice.setPassword(rw[1]);
				smartDevice.setPath(rw[2]);
				for (int i = 3; i < rw.length-1; i+=2) {
					SmartOrder order = new SmartOrder();
					 order.setSmartOrder(rw[i]);
					 order.setSmartRespense(rw[i+1]);
					order.save();
					smartDevice.getSmartOrders().add(order);
				}
				smartDevice.save();
				Intent i = new Intent(Config.notif2adddevice);
				i.putExtra("result", rawResult.getText());
				mLocalBroadcastManager.sendBroadcast(i);
				finish();


smartdevice就是要保存的设备的类,包括名字,密码,发送的指令,响应的指令,设备蓝牙物理地址等,这是根据信息特定的排列存入的,以避免随便扫一个二维码就加一个设备。在最后发送一个broadcast,通知上一个activity添加设备,然后退出扫描,设备添加成功。
mLocalBroadcastManager = LocalBroadcastManager.getInstance(getActivity());
        mReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(Config.notif2adddevice)) {
                    int drawable = 0;
                    SmartDevice smartDevice = DataSupport.findLast(SmartDevice.class, true);
                    devices.add(smartDevice);

                    if (smartDevice.getName().contains("灯")) {
                        drawable = R.drawable.light_on;
                    } else if (smartDevice.getName().contains("门")) {
                        drawable = R.drawable.door_on;
                    } else if (smartDevice.getName().contains("路由器")) {
                        drawable = R.drawable.luyouqi_on;
                    } else {
                        drawable = R.drawable.switch_on;
                    }
                    smartDevice.setDrawable(drawable);
                    smartDevice.update(DataSupport.count(SmartDevice.class));
                    datas.add(datas.size() - 1, new CellData(smartDevice.getName(), drawable));
                    adapter.notifyDataSetChanged();

                }

            }

        };
        mLocalBroadcastManager.registerReceiver(mReceiver, filter);


上面是接受broadcast的主要代码,我主要想在所有设备的最后加一个添加设备的按钮,所以每次添加设备都添加在倒数第二个,最后一个是添加按钮。

二,关于读取信息

关于读取信息是挺麻烦的事情,上次下载的例子是使用thread的,但是要实现异步,还是用asynctask。还要区分蓝牙连接,和网络连接,开始想到的一个方法是,分别写一个读取,到时后来发现要很多冗余的代码,所以把他写成一个,主要代码如下:
public class ReadMesThread extends AsyncTask {
    private InputStream mmInStream;
    int bytes;
    boolean isReading = true;
    public ReadMesThread(InputStream mmInStream){
        this.mmInStream = mmInStream;
    }
    @Override
    protected Object doInBackground(Object[] objects) {
        while (!isCancelled()) {
            byte[] buffer = new byte[256];
            if (mmInStream != null) {
                try {
                    bytes = mmInStream.read(buffer);
                    String readStr = new String(buffer, 0, bytes);
                    String str =  bytes2HexString(buffer).replaceAll("00", "").trim();
                    Log.i("result", str);
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.i("result", "standbyfail");
                    return null;
                }

            }
        }
        return null;
    }
    private String bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }
}


一个线程控制两个信息读取,非常方便。在最后的一个方法是将字节转换成字符用的,因为发送到设备的数据必须是十六进制的,所以必须要转换。但上面的代码其实是不够严谨的,为什么呢?假设现在是使用网络连接,读到的数据有可能会出现StringIndexOutOfBoundsException这个异常,这里必须捕捉,并处理异常,代码要改成这样:
try {
                    bytes = mmInStream.read(buffer);
                    String readStr = new String(buffer, 0, bytes);
                    String str =  bytes2HexString(buffer).replaceAll("00", "").trim();
                    Log.i("result", str);
                } catch (IOException e) {
                    handler.obtainMessage(Config.TIMEOUT).sendToTarget();
                    e.printStackTrace();
                    Log.i("result", "standbyfail");
                    return null;
                }catch (StringIndexOutOfBoundsException siob){
                    handler.obtainMessage(Config.SIOOBE).sendToTarget();
                }
使用handler在线程之间的通信,处理异常。
在读取信息的过程中,我还遇到一个很常见的错误,就是在一个activity中要是有一个执行长时操作的asynctask,activity被销毁的时候,那个asynctask是不会被销毁的,以至于下次再打开那个activity的时候,所有asynctask都跑不起来了,asyntask的生命周期被改变了,所以activity退出的时候一定要cancel掉asyntask,并且置空,例如:
if(connectThread!=null) {
            connectThread.cancel(true);
            connectThread = null;
        }


这种错误编译器是不报错的,非常隐秘,所以要切记!

三,总结

这次的项目是自己一个完成的,感觉挺累的,不过也充满了乐趣,学到很多东西啊

项目的demo(不全)地址: 点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: