【原创】对于一些Android开发过程中坑爹、细小,但又重要的错误的总结

对于一些Android开发过程中总有些很坑爹的错误,绕了很大一圈,最后发现是一行代码放错位置,或者少了几句声明等等。

在此,我就分享下个人在android开发过程中遇到的一些问题,也是作为一份备忘~

调试Android程序的方法(我都是用真机调试,模拟器太慢了,不爽):

  1. 我会用System.out.println();作为信息打印,类似与单片机调试中的串口打印,可以直观的看到程序执行到哪里
  2. 我会查看运行过程中的error,帮助自己定位错误和网上搜资料(虽然有很多错误考看这个还是摸不着头脑,但对有些简单的错误还是很有帮助的)
  3. 在调一些网络通信的程序时,我会在PC端写一个服务端java程序,有时还会用到wireshark这个网络数据包分析软件,这个工具可以清楚地看到网络中实际的数据,很方便
  4. 在调试多进程、有关SD等方面的程序时,我偶尔会用DDMS来对程序进行监测

以上4点中,我一般用前三种就够了,第4种网上很多人说是什么开发Android必备的,不过我用的很少,可能是我水平还不到家吧

问题汇总:

1、使用UDP来进行网络通信时,由于其receive方法是阻塞的,对于由发送转为接收模式的应用程序,如果发送请求丢包,则该程序会一直阻塞,而不再发送请求,一个实用的方法是UDP套接字的setSoTimeout();方法,可以设定其接收等待时间,以便超时后再次发送请求,保证其可靠性。

2、使用Google的Map-API来进行开发时,<uses-library android:name="com.google.android.maps" />的声明要放在<application></>标签对中,这个是对调用的lib库的声明,不像对授权的声明可以放在<application></>的外面,我就说这里搞错了,然后搞了一天,程序还是打开错误

 1 <application android:icon="@drawable/icon" android:label="@string/app_name">
 2         <activity android:name=".ParkingWorld"
 3                   android:label="@string/app_name">
 4             <intent-filter>
 5                 <action android:name="android.intent.action.MAIN" />
 6                 <category android:name="android.intent.category.LAUNCHER" />
 7             </intent-filter>
 8         </activity>
 9         <activity
10             android:name=".HomeActivity"
11             android:label="@string/location">
12         </activity>
13         <activity
14             android:name=".LocationMap"
15             android:label="@string/location">
16         </activity>
21         <!-- 声明需要使用Google Map API -->
22         <uses-library android:name="com.google.android.maps" />
23     </application>

3、使用Google的Map-API来进行开发时,遇到地图MapView组件显示网格,并且有“MapActivity:Couldn't get connection factory client”的error,这可能是由于一下几个原因造成:(类似文章可参考http://our2848884.blog.163.com/blog/static/1468548342011625102639660/)

a.Google API Key申请。试着用错误的Google API Key运行程序,地图得到的只是空格。

key的申请可以参考http://choha.iteye.com/blog/1132841

这里为了得到正确的密匙有一点要注意,那就是产生key的方式不同会影响key是否能用,下面的方法我用着可以:

在cmd中执行keytool -list -alias androiddebugkey -keystore “你的debug keystore位置” -storepass android -keypass android

b.“INTERNET”使用权限(允许应用程序访问网络)正确添加了如下语句:<uses-permission android:name="android.permission.INTERNET"/>

c.使用Google地图的函数库语句正确添加了。 <uses-library android:name="com.google.android.maps"/>,且置于</application>标签前。

4、使用DatagramSocket类创建UDP的套接字,使用Socket、SeverSocket进行TCP的套接字通信时,使用完后要记得调用其close方法,否则端口会被一直占用,导致错误;而且close语句的位置也很重要,我在一个activity中要多次使用套接字来发数据,本想使用一个套接字解决问题,在最后的Stop();或者Destory();方法中将其close,但结果行不通,而我创建一个进程,进程每次执行开始创建一个,进程执行结束时套接字close,这样程序就不会报错,且稳定性也不错,对于那些时常需要刷新数据的应用来说很实用。

5、使用TabHost时,要注意在TabActivity中不能有setContentView(R.layout.main);这样的设置布局的语句,因为TabHost其本身就是用来设置布局的,否则会产生以下错误:Caused by: java.lang.RuntimeException: Your content must have a TabHost whose id attribute is 'android.R.id.tabhost'

6、当你在A工程中调试X.java时,如果你同时在eclipse中有另一个B工程中也有同名文件X.java,则在双击打印出来的错误信息时,eclipse可能会帮你定位到B工程的X.java中,让你看了半天也没找到哪里有错误,这时你可以先把B工程从eclipse删去,再重新双击打印出来的错误信息,eclipse就会帮你正确定位啦。

7、java中的乘方运算用Math.pow(底数, 指数);方法,而不使用"^"符号,"^"在java中表示异或。

8、在使用TextView的setText方法时,注意其重载性,若要要将int整型作为参数时,编译器认为你的参数是个资源ID,找不到对应的ID时,会出现类似以下的报错:android.content.res.Resources$NotFoundException: String resource ID #0xfe                                       而如果你是要显示这个int型数据,我通常会用  “”+数据  的方法利用“+"符号的重载性,将int数据直接转为String类型。当然,也可以用Integer.valueOf(int i).toString将其转为String类型。

9、使用套接字传数据使用以下方法时,虽然String类型中是用char型来存储数据的,但在使用getBytes()方法后,有的数据,比如char型0x0001会变为一个字节的byte型0x01,而不是两个字节0x00和0x01,但很多时候其还是会变为两个字节,比如中文编码。这可以用wireshark抓包来看,当然也可以直接调用类的length()方法,再打印查看。

1 byte dataSend[] = str.getBytes();  //把传输内容分解成字节*/3 //创建一个DatagramPacket对象,并指定要讲这个数据包发送到网络当中的哪个、地址,以及端口号
4 DatagramPacket packetSend = new     DatagramPacket(dataSend,dataSend.length,serverAddress,dstPort);
5 //调用socket对象的send方法,发送数据
6 socket.send(packetSend);

因此在用一个字节表达数据时,为防止String转byte[]时的不确定性,我就直接用byte[]赋给dataSend[],也可以使用String的getBytes(String charsetName)方法

Returns a new byte array containing the characters of this string encoded using the named charset.
 1 byte by[] = new byte[4];
 2 by[0] = ledNum;
 3 by[1] = (byte)(Integer.parseInt(strR1));
 4 by[2] = (byte)(Integer.parseInt(strG1));
 5 by[3] = (byte)(Integer.parseInt(strB1));
 6 byte dataSend[] = by;
 7 //创建一个DatagramPacket对象,并指定要讲这个数据包发送到网络当中的哪个、地址,以及端口号
 8 DatagramPacket packetSend = new     DatagramPacket(dataSend,dataSend.length,serverAddress,dstPort);
 9 //调用socket对象的send方法,发送数据
10 socket.send(packetSend);

 

10、在使用TabHost时应注意其Activity的生命周期,如果不加 Intent.FLAG_ACTIVITY_CLEAR_TOP 这个flag,则Tab之间切换时,Activity只是0nPause();而不执行onStop();和onDestroy(); 并且在设置 addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 之后,切换到另一个Activity会调用另一个Activity的OnCreat方法

1 tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator(getString(R.string.park),
2                 getResources().getDrawable(android.R.drawable.star_on))
3                         .setContent(new Intent(this, ParkActivity.class)
4                                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));  //这句用来清空之前所有的activity

 11、从XML文件中获取字符串的方法 getString(R.string.my_str);

 12、在 handlerSocket.post(update); 之后又在update中递归调用 handlerSocket.postDelayed(this, 2000); 则可能会导致跳转到另一个Activity时,update仍会一次又一次地执行,这时可以在跳出Activity的触发函数,如onPause,onStop函数中加入 handlerSocket.removeCallbacks(update); 如果还是不行的话可以使用全局开关变量,runFlag(自己取的名字)。在跳入Activity的触发函数,如onCreat,onResume函数中runFlag=1,而在跳出Activity的触发函数runFlag=0。并且使用runFlag来控制 handlerSocket.postDelayed(this, 2000);  如下列代码

 1 @Override   
 2 protected void onCreate(Bundle savedInstanceState)
 3 {
 4     ......
 5     runFlag = 1;
 6     ......
 7     ......
 8     update =new Runnable(){    
 9     @Override
10     public void run() {
11         ......
12         if(runFlag == 1){
13             handlerSocket.postDelayed(this, 2000);
14         }
15     }
16     handlerSocket.post(update);
17 }
18 @Override
19 protected void onPause() {
20     // TODO Auto-generated method stub
21     super.onPause();
22     //handlerSocket.removeCallbacks(update);
23     runFlag = 0;
24 }

 

 

 

未完待续。。。

 

posted @ 2012-05-19 17:34 maliqian 阅读(...) 评论(...) 编辑 收藏