开发日志 170214

恩,第一次写开发日志。

安卓的项目,毕设的一部分,智能小船遥控器。目前两边已经可以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,所以除了手动维护一份“消息-消息含义”列表,有没有优雅一点的方法来解决这个问题?

已在知乎提问:https://www.zhihu.com/question/55813767

发表评论