只能包含字母,单词首字母出第一个外,都为大写,其他字母都为小写
只能包含字母和_,字母全部大写,单词之间用_隔开
命名模式为:view缩写_模块名称_view的逻辑名称
view的缩写详情如下
LayoutView:lv
RelativeView:rv
TextView:tv
ImageView:iv
ImageButton:im
Button:btn
命名模式为:逻辑名称+view缩写
建议:如果layout文件很复杂,建议将layout分成多个模块,每个模块定义一个moduleViewHolder,其成员变量包含所属view
命名模式:activity名称_功能模块名称_逻辑名称/activity名称_逻辑名称/common_逻辑名称
strings.xml中,使用activity名称注释,将文件内容区分开来
命名模式:activity名称_逻辑名称/common_逻辑名称
字符型转数字型,如果转换失败一定要有缺省值;
服务端响应数据是否有效判断;
针对不同的客户端打不同的包,唯一的区别是versionName,apk文件名为versionName.apk
在升级时,要将自己的versionCode和versionName一并传给服务端,如果需要升级,则下载versionName相对应的apk
关于是否要强制升级:
1).不管何种情况都强制升级
2).判断用户的版本和当前最新版本,如果兼容则强制升级,否则可选;
http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读。
在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外。
item中如果包含有webimage,那么最好异步加载
当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来
如果BaseAdapter的实体类有属性非常消耗内存,可以将保存到文件;为提高性能,可以进行缓存,并限制缓存大小。
及时的销毁(Activity的onDestroy时将bitmap回收,在被UI组件使用后马上进行回收会抛RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap) 设置一定的采样率(有开发者提供的图片无需进行采样,对于有用户上传或第三方的大小不可控图片,可进行采样减少图片所占的内存),从服务端返回图片,建议同时反馈图片的size 巧妙的运用软引用 drawable对应resid的资源,bitmap对应其他资源 任何类型的图片,如果获取不到(例如文件不存在,或者读取文件时跑OutOfMemory异常),应该有对应的默认图片(默认图片放在在apk中,通过resid获取);
ui组件需要用到的图片是apk包自带的,那么一律用setImageResource或者setBackgroundResource,而不要根据resourceid
注意:get(getResources(), R.drawable.btn_achievement_normal)该方法通过resid转换为drawable,需要考虑回收的问题,如果drawable是对象私有对象,在对象销毁前是肯定不会释放内存的。
临时的activity及时finish
主界面设置为singleTask
一般界面设置为singleTop
获取用户的地理位置信息时,在需要获取数据的时候打开GPS,之后及时关闭掉
说到编程,就不得不提到编程规范,好的编程规范应该是每个人都要遵守的好习惯,个人觉得也应该是我们从开始学习编程就应该掌握的一个技能,至于为什么要严格遵守编程规范,我就不做过多的解释,这里有一篇文章讲的非常不错为什么谷歌要执行严格的代码编写规范,今天整理了下java领域的编程规范,记录并分享在此。
每个文件的开头都应该有一句版权说明。然后下面应该是package包语句和import语句,每个语句块之间用空行分隔,然后是类或接口的定义,在Javadoc注释中,应描述类或接口的用途。
/*
* @creator Storm
* @created_at 2013-7-16 上午9:54:34
* Copyright (C) 2013 BOOHEE. All rights reserved.
*/
package com.boohee.recipe;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.widget.ListView;
public class OrderActivity extends PayActivityBase {
...
}
个人不推荐在每个类或者自建的public方法标注过多的Javadoc注释,如果你的方法或者类需要标注非常详细的注释才能让人理解,那么我想你的类或者方法应该考虑进行重构了,或许你应该起一个更好的名字来代替。当然,某些特殊情况,如包含很复杂的业务逻辑与算法,这就不得不标注详细点的Javadoc注释了。
为了把规模控制在合理范围内,方法应该保持简短和重点突出。不过,有时较长的方法也是合适的,所以对方法的代码长度并没有硬性的限制。如果方法代码超过了15行(最多不应该超过20行),就该考虑是否可以在不损害程序结构的前提下进行分拆。
字段应该定义在文件开头,或者紧挨着使用这些字段的方法之前。
局部变量的作用范围应该是限制为最小的(Effective Java第29条)。使用局部变量,可以增加代码的可读性和可维护性,并且降低发生错误的可能性。每个变量都应该在最小范围的代码块中进行声明,该代码块的大小只要能够包含所有对该变量的使用即可。
应该在第一次用到局部变量的地方对其进行声明。几乎所有局部变量声明都应该进行初始化。如果还缺少足够的信息来正确地初始化变量,那就应该推迟声明,直至可以初始化为止。
本规则存在一个例外,就是涉及try-catch语句的情况。如果变量是用方法的返回值来初始化的,而该方法可能会抛出一个checked异常,那么必须在try块中进行变量声明。如果需在try块之外使用该变量,那它就必须在try块之前就进行声明了,这时它是不可能进行正确的初始化的。
// Instantiate class cl, which represents some sort of Set
Set s = null;
try {
s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
throw new IllegalArgumentException(cl + " not instantiable");
}
// Exercise the set
s.addAll(Arrays.asList(args));
但即便是这种情况也是可以避免的,把try-catch 块封装在一个方法内即可:
Set createSet(Class cl) {
// Instantiate class cl, which represents some sort of Set
try {
return (Set) cl.newInstance();
} catch(IllegalAccessException e) {
throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
throw new IllegalArgumentException(cl + " not instantiable");
}
}
// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));
除非理由十分充分,否则循环变量都应该在for语句内进行声明:
for (int i = 0; i < n; i++) {
doSomething(i);
}
和
for (Iterator i = c.iterator(); i.hasNext(); ) {
doSomethingElse(i.next());
}
我们的代码块缩进使用4个空格。尽量不使用制表符tab。如果存在疑惑,与前后的其它代码保持一致即可。 我们用8个空格作为换行后的缩进,包括函数调用和赋值。例如这是正确的:
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
而这是错误的:
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
例如:
public class MyClass {
public static final int SOME_CONSTANT = 42;
public int publicField;
private static MyClass sSingleton;
int mPackagePrivate;
private int mPrivate;
protected int mProtected;
}
大括号不单独占用一行;它们紧接着上一行书写。就像这样:
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
我们需要用大括号来包裹条件语句块。不过也有例外,如果整个条件语句块(条件和语句本身)都能容纳在一行内,也可以(但不是必须)把它们放入同一行中。也就是说,这是合法的:
if (condition) {
body();
}
这也是合法的:
if (condition) body();
但这是非法的:
if (condition)
body(); // bad!
每行代码的长度应该不超过100个字符。
有关本规则的讨论有很多,最后的结论还是最多不超过100个字符。
例外:如果注释行包含了超过100个字符的命令示例或者URL文字,为了便于剪切和复制,其长度可以超过100个字符。
例外:import行可以超过限制,因为很少有人会去阅读它。这也简化了编程工具的写入操作。
Annotation应该位于Java语言元素的其它修饰符之前。 简单的marker annotation(@Override等)可以和语言元素放在同一行。 如果存在多个annotation,或者annotation是参数化的,则应按字母顺序各占一行来列出。
对于Java 内建的三种annotation,Android标准的实现如下:
Deprecated:只要某个语言元素已不再建议使用了,就必须使用Deprecated annotation。如果使用了Deprecated annotation,则必须同时进行deprecated Javadoc标记,并且给出一个替代的实现方式。此外请记住,被Deprecated的方法仍然是能正常执行的。
Override:只要某个方法覆盖了已过时的或继承自超类的方法,就必须使用Override annotation。
例如,如果方法使用了@inheritdocs Javadoc标记,且继承自超类(而不是interface),则必须同时用@Override标明覆盖了父类方法。
当需要使用@SuppressWarnings annotation时,必须在前面加上TODO注释行,用于解释“不可能消除”警告的条件。通常是标明某个令人讨厌的类用到了某个拙劣的接口。比如:
// TODO: The third-party class com.third.useful.Utility.rotate() needs generics
@SuppressWarnings("generic-cast")
List<String> blix = Utility.rotate(blax);
如果需要使用SuppressWarnings annotation,应该重新组织一下代码,把需要应用annotation的语言元素独立出来。
Good Bad
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
class Html class HTML
String url String URL
long id long ID
如何对待简称,JDK和Android底层代码存在很大的差异。因此,你几乎不大可能与其它代码取得一致。别无选择,把简称当作完整的单词看待吧。
对那些临时性的、短期的、够棒但不完美的代码,请使用TODO注释。
TODO注释应该包含全部大写的TODO,后跟一个冒号:
// TODO: Remove this code after the UrlTable2 has been checked in.
和
// TODO: Change this to use a flag instead of a constant.
记录日志会对性能产生显著的负面影响。如果日志内容不够简炼的话,很快会丧失可用性。日志功能支持五种不同的级别。以下列出了各个级别及其使用场合和方式。
ERROR: 该级别日志应该在致命错误发生时使用,也就是说,错误的后果能被用户看到,但是不明确删除部分数据、卸装程序、清除数据区或重新刷机(或更糟糕)就无法恢复。该级别总是记录日志。需要记录ERROR级别日志的事件一般都应该向统计信息收集(statistics-gathering )服务器报告。
WARNING: 该级别日志应该用于那些重大的、意外的事件,也就是说,错误的后果能被用户看到,但是不采取明确的动作可能就无法无损恢复,从等待或重启应用开始,直至重新下载新版程序或重启设备。该级别总是记录日志。需记录WARNING级别日志的事件也可以考虑向统计信息收集服务器报告。
INFORMATIVE: 该级别的日志应该用于记录大部分人都会感兴趣的事件,也就是说,如果检测到事件的影响面可能很广,但不一定是错误。应该只有那些拥有本区域内最高级别身份认证的模块才能记录这些日志(为了避免级别不足的模块重复记录日志)。该级别总是记录日志。
DEBUG: 该级别的日志应该用于进一步记录有关调查、调试意外现象的设备事件。应该只记录那些有关控件运行所必需的信息。如果debug日志占用了太多的日志空间,那就应该使用详细级别日志(verbose)才更为合适。
即使是发行版本(release build),该级别也会被记录,并且需用if (LOCAL_LOG)或if (LOCAL_LOGD)语句块包裹,这里的LOCAL_LOG[D]在你的类或子控件中定义。这样就能够一次性关闭所有的调试日志。因此在if (LOCAL_LOG)语句块中不允许存在逻辑判断语句。所有日志所需的文字组织工作也应在if (LOCAL_LOG)语句块内完成。如果对记录日志的调用会导致在if (LOCAL_LOG)语句块之外完成文字组织工作,那该调用就必须控制在一个方法内完成。
还存在一些代码仍然在使用if (localLOGV)。这也是可以接受的,虽然名称不是标准的。
注意:
除了VERBOSE级别外,在同一个模块中同一个错误应该尽可能只报告一次:在同一个模块内的一系列层层嵌套的函数调用中,只有最内层的函数才返回错误;并且只有能为解决问题提供明显帮助的时候,同一模块中的调用方才写入一些日志。
除了VERBOSE级别外,在一系列嵌套的模块中,当较低级别的模块对来自较高级别模块的非法数据进行检测时,应该只把检测情况记录在DEBUG日志中,并且只记录那些调用者无法获取的信息。特别是不需要记录已经抛出异常的情况(异常中应该包含了全部有价值的信息),也不必记录那些只包含错误代码的信息。当应用程序与系统框架间进行交互时,这一点尤为重要。系统框架已能正确处理的第三方应用程序,也不应该记录大于DEBUG级别的日志。仅当一个模块或应用程序检测到自身或来自更低级别模块的错误时,才应该记录INFORMATIVE及以上级别的日志。
如果一个通常要记录日志的事件可能会多次发生,则采取一些频次限制措施或许是个好主意,以防日志被很多重复(或类似)的信息给撑爆了。
网络连接的丢失可被视为常见现象,也是完全可以预见的,不应该无缘无故就记录进日志。影响范围限于应用程序内部的网络中断应该记录在DEBUG或VERBOSE级别的日志中(根据影响的严重程度及意外程度,再来确定是否在发行版本中也记录日志)。
有权访问的文件系统或第三方应用程序发起的系统空间满,应该记录大于INFORMATIVE级别的日志。
来自任何未授信源的非法数据(包括共享存储上的任何文件,或来自任何网络连接的数据)可被视为可预见的,如果检测到非法数据也不应该记录大于DEBUG级别的日志(即使记录也应尽可能少)。
请记住,对字符串使用+操作符时,会在后台以默认大小(16个字符)缓冲区创建一个StringBuilder对象,并且可能还会创建一些其它的临时String对象。换句话说,显式创建StringBuilders对象的代价并不会比用’+’操作符更高(事实上效率还将会提高很多)。还要记住,即使不会再去读取这些日志,调用Log.v()的代码也将编译进发行版中并获得执行,包括创建字符串的代码。
所有要被人阅读并存在于发行版本中的日志,都应该简洁明了、没有秘密、容易理解。这里包括所有DEBUG以上级别的日志。
只要有可能,日志就应该一句一行。行长最好不超过80或100个字符,尽可能避免超过130或160个字符(包括标识符)的行。
报告成功的日志记录绝不应该出现在大于VERBOSE级别的日志中。
用于诊断难以重现事件的临时日志应该限于DEBUG或VERBOSE级别,并且应该用if语句块包裹,以便在编译时能够一次全部关闭。
小心日志会泄漏隐私。应该避免将私人信息记入日志,受保护的内容肯定也不允许记录。这在编写系统框架级代码时尤为重要,因为很难预知哪些是私人信息和受保护信息。
绝对不要使用System.out.println() (或本地代码中的printf())。System.out 和 System.err会重定向到/dev/null,因此print语句不会产生任何可见的效果。可是,这些调用中的所有字符串创建工作都仍然会执行。
日志的黄金法则是:你的日志记录不会导致其它日志的缓冲区溢出,正如其他人的日志也不会让你的溢出一样。
我们的最终想法是:保持一致。如果你正在编写代码,请花几分钟浏览一下前后的其它代码,以确定它们的风格。如果它们在if语句前后使用了空格,那你也应该遵循。如果它们的注释是用星号组成的框框围起来的,那也请你照办。
保持风格规范的重点是有一个公共的代码词汇表,这样大家就可以把注意力集中于你要说什么,而不是你如何说。我们在这里列出了全部的风格规范,于是大家也知道了这些词汇。不过本地化的风格也很重要。如果你要加入的代码和已存在的代码风格迥异,那就会突然打破阅读的节奏。请努力避免这种情况的发生。
Android事件处理机制是基于Listener实现的,比如触摸屏相关的事件,是通过OnTouchListener实现的;而手势是通过OnGestureListener实现的,那么这两者有什么关联呢?
OnTouchListener接口中包含一个onTouch()方法,直接看一个例子:
public class MainActivity extends Activity implements OnTouchListener {
public void onCreate(Bundle outState) {
super.onCreate(outState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(this, "Touch Touch", Toast.LENGTH_SHORT).show();
return false ;
}
}
我们可以通过MotionEvent的getAction()方法来获取Touch事件的类型,包括 ACTION_DOWN(按下触摸屏), ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)和ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合getRawX()、 getRawY()、getX()和getY()等方法来获取坐标后,我们可以实现诸如拖动某一个按钮,拖动滚动条等功能。
可以看到OnTouchListener只能监听到三种触摸事件,即按下,移动,松开,如果想要监听到双击、滑动、长按等复杂的手势操作,这个时候就必须得用到OnGestureListener了。
接着上面的例子,这次加入手势监听:
public class MainActivity extends Activity implements OnTouchListener, OnGestureListener {
private GestureDetector mGestureDetector;
public void onCreate(Bundle outState) {
super.onCreate(outState);
setContentView(R.layout.main);
mGestureDetector = new GestureDetector(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
public boolean onDown(MotionEvent arg0) {
Log.i("MyGesture", "onDown");
Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
return true;
}
// 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发, 注意和onDown()的区别,强调的是没有松开或者拖动的状态
public void onShowPress(MotionEvent e) {
Log.i("MyGesture", "onShowPress");
Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
}
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
public boolean onSingleTapUp(MotionEvent e) {
Log.i("MyGesture", "onSingleTapUp");
Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
return true;
}
// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.i("MyGesture", "onFling");
Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
return true;
}
// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.i("MyGesture", "onScroll");
Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
return true;
}
// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发
public void onLongPress(MotionEvent e) {
Log.i("MyGesture", "onLongPress");
Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
}
}
本示例中,用到了OnGestureListener接口的onScroll()和OnFling()方法,涉及到了Android系统坐标及触摸MotionEvent e1和e2、速度velocityX、velocityY等值,那么这里就顺便补充下Android屏幕坐标系如下图:
(1)MotionEvent中 e1是手指第一次按上屏幕的起点,e2是抬起手指离开屏幕的终点,根据上图Android屏幕坐标系可知:
手指向右滑动,终点(e2)在起点(e1)的右侧,有e2.getX() - e1.getX() 大于0 手指向左滑动,终点(e2)在起点(e1)的左侧,有e2.getX() - e1.getX() 小于0 手指向下滑动,终点(e2)在起点(e1)的下侧,有e2.getY() - e1.getY() 大于0 手指向上滑动,终点(e2)在起点(e1)的上侧,有e2.getY() - e1.getY() 小于0
(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
distanceX,是前后两次call的X距离,不是e2与e1的水平距离 distanceX,是前后两次call的Y距离,不是e2与e1的垂直距离 具体数值的方向,请详见上图(中)
(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
velocityX,是X轴的每秒速度 velocityY,是Y轴的每秒速度 具体数值的方向,请详见上图(右) 仔细观察可以发现:velocityX、velocityY的方向与distanceX、distanceY方向正好相反
周末发现一些比较有用的android开发常用的工具,里面大部分是自己经常用的,还有一些暂时很少用,暂且在这里记录下,以后一定同样会经常用到的。
这个工具是用来添加、更新Android SDK的组件的,例如新的API。
这是Eclipse的Android开发者查件,为Android开发提供了一个可视化的集成开发环境。
在Android开发工具包当中有一个调试工具,Dalvik Debug Monitor Server (DDMS)。这个工具提供了端口转发,截屏,堆栈,进程信息,日志,信号状态信息,模拟来电,短信,模拟地理位置信息等。
这是Android提供的日志系统。这个系统提供了一个收集、查看系统调试信息的机制。不同的App,不同的系统组件生成的日志将被同一收集、存储起来。我们可以通过logcat的命令去筛选,查看日志信息。
这个工具可以帮助开发者调试、优化用户界面。它可以为App的用户界面结构生成一个图形的展示方式,并且提供了显示的放大功能。
这个工具可以优化Android程序文件(.apk),可以使应用程序运行更快。在Android平台中,数据文件存储在apk文件中,可以多进程的访问,如果你开发过Win32可能知道程序的粒度对齐问题,不错虽然不是PE格式的文件,在Zip中一样,资源的访问可以通过更好的对其优化,而zipalign使用了4字节的边界对齐方式来影射内存,通过空间换时间的方式提高执行效率。
这个很简单啦,就是模拟器!
Android Debug Bridge(adb) 是一个通用的命令行工具用来和模拟器或者连接到计算机的Android设备通信。
ADB常用的几个命令
1.查看设备
adb devices
这个命令是查看当前连接的设备, 连接到计算机的android设备或者模拟器将会列出显示
2.安装软件
adb install <apk文件路径>
这个命令将指定的apk文件安装到设备上
3.卸载软件
adb uninstall <软件名>
adb uninstall -k <软件名>
如果加 -k 参数,为卸载软件但是保留配置和缓存文件.
4.登录设备shell
adb shell
adb shell <command>
这个命令将登录设备的shell. 后面加command将是直接运行设备命令, 相当于执行远程命令
5.从电脑上发送文件到设备
adb push <本地路径> <远程路径>
用push命令可以把本机电脑上的文件或者文件夹复制到设备(手机)
6.从设备上下载文件到电脑
adb pull <远程路径> <本地路径>
用pull命令可以把设备(手机)上的文件或者文件夹复制到本机电脑
7.重新挂载文件系统
adb remount
8.重启手机
adb reboot
9.重启到Recovery界面
adb reboot recovery
10.显示帮助信息
adb help
这个命令将显示帮助信息
在linux下配置测试环境时,经常遇到代理服务器配置的相关问题,在这里总结一些,为以后节省些时间。 也希望对需要的人有所帮助。
一般是把如下环境变量的设置放到/etc/profile.d/proxy.sh文件中。 对于没有系统权限的用户,可以将下面的内容添加到自己用户目录下的.profile文件中。 这样登录后,大多数的应用程序都可以正常上网。
#proxy=http://用户名:密码@ProxyURL或IP地址:端口号
proxy=http://ProxyURL或IP地址:端口号
export http_proxy=$proxy
export https_proxy=$proxy
export ftp_proxy=$proxy
export no_proxy=以逗号分隔的除外列表
CentOS下,设置了上述proxy后,yum还是有不能正确下载有些资源包的情况,可以通过在 /etc/yum.conf文件中添加如下内容来单独设置proxy。
proxy=http://ProxyURL或IP地址:端口号
proxy_username=用户名
proxy_password=密码