恩,第一次写开发日志。
安卓的项目,毕设的一部分,智能小船遥控器。目前两边已经可以ping通了,延迟计算也可以了,消息队列也实现了。目前一个没解决的问题是:如何优雅的用int变量标识消息类型。另外,ping测试的代码有点简单。
还有就是一个数据校验的问题。安全性应该是不太需要担心,因为WiFI有WPA2保护了,因此我没用加密。不过信号很差的时候,可能会GG,因此可能需要进行完整性校验?
zhc说不需要,因为WPA保证了物理层传输的完整性。此事暂且留待以后解决(实在不行就在最后加上1Byte的累加和校验)。
坑
先说说这几天踩到的坑:
主线程不能进行网络IO等操作
最开始写原型的时候,不准备搞太麻烦,先写个ping程序试试。OK说干就干,在onCreate里面写了个UDP发包,然后程序崩溃了,输出了一大堆东西。 这么一大堆东西谁会仔细看啊喂!
于是开始百度,无果,仔细看日志,忽略了那一大堆搞不明白的at xxx balabala,看到android.os.NetworkOnMainThreadException。OK,感情Google直接禁止了在UI线程执行网络操作了,难怪会GG,新开一个线程好了……。
非主线程不能进行UI更新操作
然后我创建了一个新的线程,丢了一个TextView进去,网络IO结束之后让子线程更新UI。好了,这下又来了:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Android官方是这么说的:
“The Android UI toolkit is not thread-safe and the view must always be manipulated on the UI thread.”
恩,好吧……
正经的方法是使用消息队列。不过呢也有办法在非主线程更新UI,Activity.runOnUiThread或View.post,安全性我暂时还没研究。具体用法如下:
runOnUiThread(new Runnable() { //更新UI @Override public void run() { // TODO Auto-generated method stub btn.setText("runOnUiThread子线程一"); } }); view.post(new Runnable(){ @Override public void run() { view.setText("No Reply!"); }
小知识
设定DatagramSocket.receive的超时时间
使用udp2boat.setSoTimeout();这个函数,当DatagramSocket.receive()超时的时候,会抛出SocketTimeoutException这个异常。处理这个异常就行了。
MessageQueue机制的使用方法
要使用消息循环,需要三个类:Message, Looper, Handler。我们在需要接受消息的线程中:
Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop();
然后在发送消息的线程中:
childThread.mHandler.sendMessage(msg);
就可以了,当然sendMessage还有一些变种,以后再研究。
疑问
Android.os.Message里面,有int arg1, arg2, what; Object obj;这样几个用来传消息的字段,根据官方的解释,arg1 arg2用于存储少量数据,obj用于传送大量数据,what用来标识消息类型。
但是不像C++的时候,enum可以自动转换为int,所以除了手动维护一份“消息-消息含义”列表,有没有优雅一点的方法来解决这个问题?