本文介绍Android开发过程中的一些基本常识,大多是一些流程、专业术语和解决问题的方法等。

一、软件开发流程

         一个完整的软件开发流程离不开策划、交互、视觉、软件、测试、维护和运营这七个环节,这七个环节并不是孤立的,它们是开发一款成功产品的前提,但每一项也都可以形成一个学科,是一个独立的岗位,随着敏捷开发的流行,以及来到了体验为王的时代,现代软件开发更多的是注重效率和敏捷,而不是循规蹈矩的遵循这些开发流程,比如软件开发的岗位不再仅仅是个技术岗位,它需要去参与前期的设计和评审、可以在视觉和交互方面提出自己的见解,在开发的过程中需要自测程序尽快解决现存问题,运营和维护的过程中也需要软件的帮助。可见现代软件开发对开发者的综合素质(这并不是facebook所讲的全栈工程师)越来越高,自称为码农或者程序猿显然是不合理的,因为这个过程是脑力劳动和体力脑动并存,称呼自己为工程师显得更为合理。

策划:需求收集(通过用户调研、灰度发布、大数据分析、竞品分析、领导拍脑袋等方式获取需求)、需求整理(将需求归类、划分优先级等)、将需求转换成解决方案(输出设计文档);

交互:从心理学(利用人性的弱点)、人性化(心智)、个性化的角度将解决方案转换成可交互的功能和界面(需要输出交互文档),比如加载等待、消息提示、页面布局、页面内和页面间的交互逻辑、页面切换动画等等,这个过程中一般会使用Axure或者PowerPoint来制作交互文档;

视觉:根据交互图,使用PhotoShop来做视觉效果,在Android上的图片格式大多是png和jpg,对于需要屏幕适配,程序又适合做屏幕适配的地方可以使用九图,格式为*.9.png。

软件:根据视觉和交互效果将需求转化为具体的实现,在实现的过程中可能会因为需求、交互或者视觉的变动导致软件实现的变动,因为策划、交互、视觉这每一个环节都可能会有信息失真的现象,或者是由于市场环境的变化、获取信息不够准确、领导拍脑袋等等情况导致软件始终处于被动状态,所以现在会提倡敏捷开发、结对编程、程序设计、同行评审、单元测试来提高程序的灵活性和稳定性;

测试:软件达到可交互的标准后,需要将可交互的程序提供测试,其中灰度发布(用户测试)、自测(开发自测)、SQA(品质保证)都算是测试;

维护和运营:通过测试程序达到稳定标准后,软件就可以上线了,软件上线后,需要去维护,用户反馈的问题要及时解决、用户有疑问要及时解答;根据后台统计信息、抓住可运营的节日、民族文化需要做运营来提高用户使用产品的粘度,让更多的用户知道、使用产品都是运营应该做的。

注:
        1、可以查看这个答案了解一个APP从创意到上线的具体流程,开发一个APP有多难?        2、可以查看笔戈科技的这篇文章了解一个手机(平板或其它电子产品也差不多)的诞生需要哪些环节,一个手机的诞生过程


二、提问的智慧

        大多数工作都是以结果为导向的,特别是软件开发这个职业,绩效考核、KPI这些都是在考核你工作的成果,所以工作更多地是需要你解决问题的能力,至于学习这个事情,还是在工作之外的时间去做吧。对于提高解决问题能力我有两个建议:

        学会学习和思考:学习的过程中要广度和深度并存,Android应用开发本身对技术功底的要求不高(因为很多底层的东西都被google、框架、开源代码给封装起来了,多数时候你只需要看ReadMe或者API知道怎么用就可以了),更多地是在你遇到问题的时候知道这个问题能够通过什么方法和方式来解决。书要看,但多逛逛论坛、QQ群、Github、StackOverflow、CSDN博客专栏对自己都是有益的。
        学会提问:你身边有很多资源,比如同事、StackOverflow、QQ技术交流群、搜索引擎,当你遇到问题的时候完全可以利用身边的资源来解决遇到的问题,如果一个问题在一个小时之内自己都不能够解决它,我就会通过搜索引擎、Github、QQ技术交流群、同事、StackOverflow(以上排序是按优先级排列的)来解决它。如果你需要好的答案你就需要有好的提问,特别是在QQ群或者论坛,在提问的过程中需要体现出你的思考,能够通过搜索引擎解决的问题坚决不问他人,这是对别人的尊重,

三、解决bug的方法

        在知道如何快速解决bug之前,你需要知道什么是bug。没有完成策划、交互、视觉要求的功能,这不叫bug,这叫功能缺陷;一个功能完成后不能正常使用也不叫bug,因为它根本还没达到可测试的标准。我认为当你的程序达到可测试标准之后发现的问题才叫bug。综合我自己解决bug的经验和知乎上的回答,总结常见的解决bug的方法有(你想要高效解决bug的前提是你能够快速定位到缺陷所在的位置,所以以下方法多数讲的是如何快速定位问题,至于真正解决bug,需要你自己修改程序才行):


I 断点调试:


以Eclipse为例:


1、打断点:


(1)打断点:


android 开发原理 android开发过程_搜索引擎




(2)清除断点:


android 开发原理 android开发过程_搜索引擎_02




2、启动调试模式的两种方式:


        (1)通过debug as启动调试程序:右键工程名-->Debug AS -->Android Application -->模拟器或者真机会弹出......watching for the debugger......的提示框,不要点击等待其自动消失 --> 此时已经进入调试模式,操作程序到达打断点的地方。


        (2)在程序运行过程中,在DDMS视图下选中要调试的程序,启动调试模式:


android 开发原理 android开发过程_android 开发原理_03




3、调试:请自行尝试F5、F6、F7、F8这几个调试的快捷键;


4、watch成员变量:在调试的过程中,比如在执行for、while、do while循环、递归、系统回调等程序时可以通过watch来观察成员变量或者方法返回值的变化情况,watch的方法:


android 开发原理 android开发过程_Android_04




注:更多关于在Eclipse IDE中调试Android程序的知识请参见:Android eclipse中程序调试



II 打印:


        打印调试的方法对于循环、异步加载、递归、JNI等代码段非常有用,特别是在循环中,在循环次数非常大时,通过打断点调试显然是一件费力的事情,这时候打印就显得更“智能”了,我通常会通过下面封装的打印调试类来输出打印信息,这个类可以打印print、log、行号、文件名、StrictMode等信息,当不需要打印信息时,只需要将DEBUG_MODE改为false就可以了:



        
1.               import android.content.Context;  
2. import android.os.StrictMode;  
3. import android.util.Log;  
4. import android.widget.Toast;  
5.   
6. /**
7.  * 调试打印类
8.  * 
9.  * */  
10. public class DebugUtils{  
11. private DebugUtils( ){  
12.           
13.     }  
14.   
15. public static void println( String printInfo ){  
16. if( Debug.DEBUG_MODE && null != printInfo ){  
17.             System.out.println( printInfo );  
18.         }  
19.     }  
20.   
21. public static void print( String printInfo ){  
22. if( Debug.DEBUG_MODE && null != printInfo ){  
23.             System.out.print( printInfo );  
24.         }  
25.     }  
26.   
27. public static void printLogI( String logInfo ){  
28.         printLogI( TAG, logInfo );  
29.     }  
30.       
31. public static void printLogI( String tag, String logInfo ){  
32. if( Debug.DEBUG_MODE && null != tag && null != logInfo ){  
33.             Log.i( tag, logInfo );  
34.         }  
35.     }  
36.   
37. public static void printLogE( String logInfo ){  
38.         printLogE( TAG, logInfo );  
39.     }  
40.       
41. public static void printLogE( String tag, String logInfo ){  
42. if( Debug.DEBUG_MODE && null != tag && null != logInfo ){  
43.             Log.e( tag, logInfo );  
44.         }  
45.     }  
46.   
47. public static void printLogW( String logInfo ){  
48.         printLogW( TAG, logInfo );  
49.     }  
50.       
51. public static void printLogW( String tag, String logInfo ){  
52. if( Debug.DEBUG_MODE && null != tag && null != logInfo ){  
53.             Log.w( tag, logInfo );  
54.         }  
55.     }  
56.   
57. public static void printLogD( String logInfo ){  
58.         printLogD( TAG, logInfo );  
59.     }  
60.       
61. public static void printLogD( String tag, String logInfo ){  
62. if( Debug.DEBUG_MODE && null != tag && null != logInfo ){  
63.             Log.d( tag, logInfo );  
64.         }  
65.     }  
66.   
67. public static void printLogV( String logInfo ){  
68.         printLogV( TAG, logInfo );  
69.     }  
70.       
71. public static void printLogV( String tag, String logInfo ){  
72. if( Debug.DEBUG_MODE && null != tag || null != logInfo ){  
73.             Log.v( tag, logInfo );  
74.         }  
75.     }  
76.       
77. public static void printLogWtf( String logInfo ){  
78.         printLogWtf( TAG, logInfo );  
79.     }  
80.   
81. public static void printLogWtf( String tag, String logInfo ){  
82. if( Debug.DEBUG_MODE && null != tag && null != logInfo ){  
83.             Log.wtf( tag, logInfo );  
84.         }  
85.     }  
86.   
87. public static void showToast( Context context, String toastInfo ){  
88. if( null != context && null != toastInfo ){  
89.             Toast.makeText( context, toastInfo, Toast.LENGTH_LONG ).show( );  
90.         }  
91.     }  
92.   
93. public static void showToast( Context context, String toastInfo, int timeLen ){  
94. if( null != context && null != toastInfo && ( timeLen > 0 ) ){  
95.             Toast.makeText( context, toastInfo, timeLen ).show( );  
96.         }  
97.     }  
98.   
99. public static void printBaseInfo( ){  
100. if( Debug.DEBUG_MODE ){  
101. new StringBuffer( );  
102. new Throwable( ).getStackTrace( );  
103.   
104. "; class:" ).append( stackTrace[ 1 ].getClassName( ) )  
105. "; method:" ).append( stackTrace[ 1 ].getMethodName( ) )  
106. "; number:" ).append( stackTrace[ 1 ].getLineNumber( ) )  
107. "; fileName:" ).append( stackTrace[ 1 ].getFileName( ) );  
108.