liujiangchuan / liujiangchuan/BlogAndroidCN
菜鸟起飞之路-Android开发年终总结(博客搬家)
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 1
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
### 以下内容本人于2016/01/07 17:16在“OhwYaa|东软知识社区”平台首发,现整理到个人博客中。原址仅内部公开:https://www.ohwyaa.com/neusoft.com/blog/bccd70b1-fa3c-4649-b363-1239f18dc9cb/view/text
已经在东软快两年了,做Android应用开发也快两年了,作为一个菜鸟程序猿(到底是鸟还是猿=.=?!),感觉今年的收获真的是很多很多。不多说了,先上技术贴,接下来分享一下遇到过的问题和积累的一点经验,希望同为Android的开发者们可以共同交流学习,请大神们多多指点。
### 1. 编程基础
**1.1 strictMode苛刻模式去检测代码编写规范**
```
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
builder.detectAll();
builder.penaltyLog();
StrictMode.VmPolicy vmp = builder.build();
StrictMode.setVmPolicy(vmp);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
```
**1.2 Android JUnit Test工具**
Test类需要继承AndroidTestCase。另外,AndroidManifest.xml文件中需要添加如下内容
```
......
```
**1.3 SQLite自增主键**
primary key类型需要设置成Integer才能自增,long型或其他不能自增。
**1.4 检索数据库表字段信息**
SQL: pragma table_info("T_TABLE_NAME")
**1.5 方法数超过65k**
问题:Unable to execute dex: Cannot merge new index 65552 into a non-jumbo instruction!
原因:Android系统中,一个Dex文件中存储方法id用的是short类型数据,所以导致dex中方法不能超过65k。
解决方法:在project.properties里添加一行dex.force.jumbo=true,clean再build一下就没问题了。(在2.3系统之前,虚拟机内存只分配了5M。)
终极解决方法:1)清理工程无用代码jar包等;2)将一些功能做成插件,动态加载。
**1.6 TextUtils工具类**
判断空字符串等方法。
**1.7 多线程**
1) 方法中如果使用成员变量的值,该值可能会受异步的影响而变化,需要加锁或转成局部变量处理;
2) 在线程中使用信号量Semaphore阻塞/释放线程;
3) 控制线程个数,设置线程优先级。
**1.8 Try catch finally return**
1) 不管有无出现异常,finally块中代码都会执行;
2) 当try和catch中有return时,finally仍然会执行;
3) finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4) finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
**1.9 xmlns:tools=http: //schemas.android.com/tools**
在xml布局中使用xmlns:tools=http: //schemas.android.com/tools命名空间
在官方文档中有说这么一句: These are attributes which are used when the layout is rendered inthe tool, but have no impact on the runtime. This is useful if you for examplewant to put sample data in your textfields for when you are editing the layout, but you don't want those attributes to affect your running app.
这些属性用于渲染布局,而不会影响到程序运行。也就是说只在预览布局时出现,在程序运行时相当于该属性不存在。这个说明非常有意思,比如我们在布局文件中想要显示一段文字时,而该文字内容在程序中可能动态变化,特别是有参数的字符串内容%1$s之类的内容,以前必须使用android:text显示,然后调整这段文字的大小颜色参数,然后完成后删除android:text属性。有了tools参数后,可以直接使用tools:text在预览时显示文字即可,省却了上面删除的麻烦。
### 2. UI及资源
**2.1 资源优化**
简单几何图形、渐变、边框等效果背景,可以在xml中绘制,不需要加载资源图片,图片资源文件尽量使用.9。
**2.2 文字设置渐变效果**
```
TextView tv = (TextView) findViewById(R.id.text);
LinearGradient gradient = new LinearGradient(0, 0, 200, 0, 0xffff0000, 0x22ff0000, Shader.TileMode.CLAMP);
tv.getPaint().setShader(gradient);
```
**2.3 setImageResource, setImageBitmap, setImageDrawable区别**
1) setImageResource:这个方法是在UI线程中对图片读取和解析的,所以有可能对一个Activity的启动造成延迟。所以如果顾虑到这个官方建议用setImageDrawable和setImageBitmap来代替。
2) setImageBitmap:实际上setImageBitmap做的事情就是把Bitmap对象封装成Drawable对象,然后调用setImageDrawable来设置图片。因此代码里面才写上了建议,如果需要频繁调用这个方法的话最好自己封装个固定的Drawable对象,直接调用setImageDrawable,这样可以减少Drawable对象。因为每次调用setImageBitmap方法都会对Bitmap对象new出一个Drawable。
3) setImageDrawable:参数是Drawable,也是可以接受不同来源的图片,方法中所做的事情就是更新ImageView的图片。上面两个方法实际上最后调用的都是setImageDrawable(setImageResource没有直接调用,不过更新的方法与setImageDrawable一样)。
所以综合来看setImageDrawable是最省内存高效的,如果担心图片过大或者图片过多影响内存和加载效率,可以自己解析图片然后通过调用setImageDrawable方法进行设置。
**2.4 ListView多次调用getView**
如果ListView的高度是wrap_content,系统不知道ListView的高度,所以多次调用其adapter的getView方法尝试计算高度。
**2.5 Inflate布局宽高**
当你用自定义的layout文件手动来inflate的时候最外层的高度值和宽度值都是无效的,这是API实现方式的问题。可以使用minHeight, minWidth.
**2.6 include布局宽高**
```
```
必须同时重载layout_width和layout_height属性,其他的layout_*属性才会起作用,否这都会被忽略掉(否则layout_below无效)。
**2.7 Padding失效**
在Layout中指定好background和padding以后,程序里面动态修改background之后padding就失效了。
解决方案:在setBackgroundResource之后重新设置一下padding。
```
int bottom = theView.getPaddingBottom();
int top = theView.getPaddingTop();
int right = theView.getPaddingRight();
int left = theView.getPaddingLeft();
theView.setBackgroundResource(R.drawable.entry_bg_with_image);
theView.setPadding(left, top, right, bottom);
```
**2.8 设置文本格式**
1)HTML
在字符串资源文件中编写如:
```
%s,Hello ]]>
```
在代码中获取该文案:
`Html.fromHtml(String.format(mContext.getText(R.string.xx).toString(), args))`
2)Spannable
html的方式好像效率不高,也可使用如下方式:
```
Spannable span = new SpannableString(test);
span.setSpan(new AbsoluteSizeSpan(18, true), 0, (length-1),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mMyTextView.setText(span);
```
### 3. 事件机制
**3.1 onTouch 和onClick并存**
先执行onTouch。onTouch是有返回值的,onClick没有,当使onTouch返回FALSE时,表示对该操作不感兴趣,不再继续响应onTouch,此时会回调onClick;当使onTouch返回TRUE时,表示对该操作感兴趣,不再执行其他任何监听的回调函数,如onClick。
**3.2 监听HOME键**
在onStop()中调用下面方法,可以判断是否是切后台动作,可实现监听HOME键,点击notification。
```
public boolean isAppOnForeground() {
// Returns a list of application processes that are running on the device
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
String packageName = getApplicationContext().getPackageName();
List appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null)
return false;
for (RunningAppProcessInfo appProcess : appProcesses) {
// The name of the process that this object is associated with.
if (appProcess.processName.equals(packageName) && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
return true;
}
return false;
}
```
**3.3 dispatchKeyEvent, onKeyDown, onKeyUp 并存**
1) 当键盘按下时触发顺序:
dispatchKeyEvent -> onUserInteraction -> onKeyDown
如果按下紧接着松开,则继续触发:
dispatchKeyEvent -> onUserInteraction -> onKeyUp
2) dispatchKeyEvent负责分发。
dispatchKeyEvent return true/false 表示拦截,不执行onKeyDown, onKeyUp;return super.dispatchKeyEvent(event),执行onKeyDown, onKeyUp;
3) 如果在Activity B的onKeyDown方法中执行finish(),不管return true/false,都会调用finish()返回到的Activity A的dispatchKeyEvent和onKeyUp方法。因此,要么选择在Activity B 的onKeyUp方法中执行finish()。要么在Activity A 中不要使用dispatchKeyEvent和onKeyUp执行操作。否则可能会存在在Activity B中点击返回键却finish掉A、B两个Activity。
**3.4 onLongClick返回值**
onLongClick需要return TRUE 表示已经消费了该事件,不再传递给其他控件。
**3.5 onInterceptTouchEvent及onTouchEvent**
onInterceptTouchEvent 是在onTouchEvent之前执行,是用来分发触发事件的。onInterceptTouchEvent:return false时调用子控件的触发事件,不执行onTouchEvent;return true时执行onTouchEvent。

通常外围的View1, View2只是布局的容器不需要响应触屏的点击事件,仅仅View3需要相应点击。但这只是一般情况,一些特殊的布局可能外围容器也要响应,甚至不让里面的View3去响应。更有特殊的情况是,动态更换响应对象。那么看一下默认的触屏事件在两个函数之间的传递流程,如下图:

以上内容是把平时的记录进行了一下简单整理,还有一些关于命名规则的菜鸟想法还没有勇气和机会去尝试,先拿出来晒晒:
1) 在coding当中,我对命名规则比较在意,有时写一个简单的方法,一半的时间我在想应该如何命名,应该使用什么访问权限,是否需要抽象,是否应该有重载等,难道我有强迫症?不会不会不会。。。我在考虑,能否在需求分析时,快速定义出应用所需的关键词并译成英文,广播给所有开发者去使用。例如需求中有“人”这个实体类,代码中可能会存在man, people, person, human等定义,但实指都是一样的,只是不同的人会翻译成不同的词。如果能够统一的话,我想会对后续维护或其他人接手开发等减少很多障碍。
2) colors.xml自定义颜色值命名方式使用RGB颜色直接命名方法,如#c9c9c9。这样做是为了保证颜色值的唯一性,避免在需求不断增加的情况下,颜色出现重复定义或命名明显存在歧义等情况。缺点就是,如果某些页面风格一致,不同页面的不同控件显示的是相同的颜色值,此时如果有需求变更批量修改这些颜色时,不能靠修改colors值实现(因为会影响其他使用该值的控件),使用冗余的定义就可以实现。我个人总结就是冗余设计的优缺点。
3) 图片资源由UI设计师统一命名并管理。如果开发人员命名,名称可能会关联他所开发的需求,而当这张图片可以被其他需求复用时,再次关联其他需求后,不合适的命名方式会降低代码可读性。例如一个心形图案,在开发者A的眼中这是收藏功能collect_icon.png,在开发者B的眼中这是点赞功能praise_icon.png,在美工眼中这是heart_icon.png,我个人认为美工的命名方式也许更合理一些。希望由美工管理图片资源的原因还以A、B两人举例,A正在开发收藏功能向美工要了心形图片,同时B正在开发点赞功能也要了心形图片,那么当天提交代码后工程中就会出现两张相同的图片了,如果不去排查工程不会有任何错误和异常,但APK无缘无故的增加了几K大小。如果由美工管理,当A、B两人要资源图片时,美工直接把命名后的资源路径给他们就好了。
_文章标题之所其名叫菜鸟“起飞”之路,也算有个双关的含义吧,因为春节准备带媳妇儿飞去澳大利亚旅了个游,考验寡人英语能力的时刻到了,机票酒店都订好了,得赶紧去计划一下详细行程和路线了。。祝各位有耐心看到这儿的人奖金多多,工作顺利,新年快乐哈。。_
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue body contains a long Android development article and references image paths such as image/3/views.PNG and image/3/touchEvent.PNG, but names no target file, test, or entry point. Read the article and repository structure first; the destination, formatting requirements, and definition of done are not specified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java, sqlite
- Domain
- content, documentation, mobile
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100