`

Android4开发入门经典 之 第十二部分:最佳实践

 
阅读更多


性能提升

有两个编写有效代码的基本规则:

1:不要做你不需要做的。
2:不分配没必要分配的内存。
 

应该尽量避免创建多余的对象,比如:

1:在一组输入数据中抽取字符串时,尝试返回源数据的子串,而非创建一个副本
2:如果你有一个返回String的方法,而且你知道它的结果将会一直被追加到StringBuffer,改变你的签名和实现,在这个函数里面直接追加,避免创建临时对象。
3:将多维数组切成与之平行的一维数组
4:一个int数组比Integer数组要好,一个公认的事实就是两个平行的int数组要比一个(int,int)对象数组要高效很多。对于其它原始数据类型亦如是

应该尽量使用Native方法 ,比如:

当处理字符串时,要毫不犹豫地使用诸如String.indexOf()、String.lastIndexOf()之类的专门方法,这些是典型的用C/C++代码实现的方法,它们可以轻易地比实现同样功能的Java循环快10-100倍

优先使用实现类,而不是接口

对于嵌入式系统来说,通过接口的引用来调用一个方法要比通过一个具体类型的引用调用virtual方法花多2倍的时间。
但是公共API除外,好的API较少考虑性能。

优先选择static而非virtual

如果你不必访问一个对象的字段,使你的方法成为static方法。它可以被更快地调用,因为它不需要一个虚拟方法来间接调用。

避免内部的Getter/Setter

在Android,虚拟方法调用代价是昂贵的,实例字段查找代价更高。沿用一般面向对象编程实践在公开接口中提供gettter和setter是合理的,但在一个类中你应该直接访问字段 。
 
访问对象字段要比访问本地变量慢得多,如下面这段: 

java代码:
for (int i = 0; i < this.mCount; i++) 
dumpItem(this.mItems[i]); 
应该写成这样: 
int count = this.mCount; 
Item[] items = this.mItems; 
for (int i = 0; i < count; i++) 
dumpItems(items[i]); 
(我们用一个显式的"this"来表明这是一个成员变量。)
同样的,不要在for语句中的第二个从句中调用方法。例如下面这段代码将会在每次迭代中都会执行一次getCount(),这是一个巨大的浪费,你可以将它的值cache为一个int。 
java代码:
for (int i = 0; i < this.getCount(); i++) 
    dumpItems(this.getItem(i)); 

缓存查询字段 , 通常,如果你将要访问一个实例字段多次,一个好的习惯就是创建一个临时变量。例如: 

java代码:
protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) { 
        if (isHorizontalScrollBarEnabled()) { 
            int size = mScrollBar.getSize(false); 
            if (size <= 0) { 
                size = mScrollBarSize; 
            } 
            mScrollBar.setBounds(0, height - size, width, height); 
            mScrollBar.setParams( computeHorizontalScrollRange(), 
                    computeHorizontalScrollOffset(), 
                    computeHorizontalScrollExtent(), false); 
            mScrollBar.draw(canvas); 
        } 
    } 

这是对成员字段mScrollBar的四次分开查找,通过将mScrollBar缓存到本地变量,四次成员字段查找变成四次本地变量引用,这样更为高效。 
同样地,方法参数作为本地变量拥有相同的性能特征。

 
声明常量为static final,主要是针对属性字段,你也可以将本地变量声明为final,然而这并无真正意义上的性能提升 。
使用增强的For循环语句
增强的For语句对于数组表现良好,但对iterable对象要小心使用,因为有额外的对象创建。对于ArrayList,你最好直接遍历它,但对于其它collections,增强的For循环语句将会等同于显式的迭代用法。
避免使用Enum类型
避免使用Float类型
嵌入式处理器很少具有硬件浮点支持,所以所有的“float”和“double”操作都是在软件上进行。某些基本的浮点操作可能会花费数微秒。
避免使用JNI

支持多种屏幕

在实际开发中,由于由于不同手机的尺寸大小,屏幕分辨率可能存在差异,这会带来很多的问题,比如:

1:图片在不同的设备上,大小显示不一
2:Layout在不同的设备上,显示不一样,可能变形了

一些基本的解决方法:

1:对于字体,尽量使用sp作为单位,其他的尽量使用dp或者dip
2:使用wrap_content, fill_parent, 或者 dp 来定义layout的尺寸大小
3:不同密度设备对应图像文件的最佳比例。
对于四种密度low-dpi, medium-dpi, high-dpi, extra high-hdpi的设备,在指定一个相同的图像文件时,分配给各种密度的图像文件的尺寸应该符合以下比例:3:4:6:9. 也就是要符合密度比例(120:160:240:360)。

举个列子,假如我们要在一个密度为160dpi的设备上使用到一个48 * 48的图像文件。那么对于其它密度的设备,我们要准备的图像文件分别是:

low-density (120dpi) : 36×36
medium-density(160dpi): 48×48
high-density (240dpi) : 72×72
high-density (360dpi): 96×96 
4:在需要的情况下,为每种尺寸的设备提供指定的layout文件。
5:在需要的情况下,为每种密度的设备提供不同的图像文件
6:不使用absoluteLayout布局

UI最佳实践

这是一份来自Moto的,关于Android UI的最佳实践,要点如下:

1:阅读UI指导方针(UI guideline)
2:理解和设计触摸模式
3:支持多种交互模式 (如键盘、轨迹球、触摸屏等)
4:使用通知(notifications)和窗口阴影(window shade)
5:支持应用间的交互
6:保持你的用户界操作面快速且敏感
7:使用窗体部件和文件夹
8:运用屏幕方向的改变
9:巧用图片
10:使用适用于多设备的布局

这是一份来自Android官方开发者博客,关于Android UI的最佳实践

不应该

1.不要照搬你在其它平台的UI设计,应该让用户感觉是在真正使用一个 Android 软件,在你的商标显示和平台整体观感之间做好平衡 
2.不要过度使用模态对话框 
3.不要使用固定的绝对定位的布局 
4.不要使用px单位,使用dp或者为文本使用sp 
5. 不要使用太小的字体

应该

1. 为高分辨率的屏幕创建资源(缩小总比放大好) 
2. 需要点击的元素要够大 
3. 图标设计遵循 Android 的准则 
4. 使用适当的间距(margins, padding) 
5. 支持D-pad和trackball导航 
6. 正确管理活动(activity)堆栈 
7. 正确处理屏幕方向变化 
8. 使用主题/样式,尺寸和颜色资源来减少多余的值 
9.和视觉交互设计师合作!!! 

设计哲学

1. 干净而不过于简单 
2. 关注内容而非修饰 
3. 保存一致,让用户容易投入其中,可附加少许变化 
4. 使用云端服务(存储和同步用户资料)来加强用户体验

优秀界面的设计准则

1. 关注用户 
2. 显示正确的内容 
3. 给予用户适当的回馈 
4. 有章可循的行为模式 
5. 容忍错误

关注用户

1. 了解你的用户(年龄,技能,文化,对你的应用的需求,使用的设备,何时何地如何使用设备) 
2. ‘用户优先’的设计心态 (用户通常是任务导向的行为模式) 
3. 更早,更频繁的由真实用户来测试

显示正确的内容 

1. 最常用的操作需要最快被用户看到并且可用 
2. 不太常用的功能可以放到菜单里面
 

给予用户适当的回馈

1. 交互式的UI元素最少需要反映出4种不同的状态 (default,disabled,focused,pressed) 
2. 保证操作的结果是清晰可见的 
3. 多给予用户进度提示,但是不要干扰他们当前的操作

有章可循的行为模式

1. 行为模式遵循用户的期望(正确的操作活动堆栈,显示用户期望看到的信息和动作) 
2. 使用合适的方式来加强功能可见性(可点击的元素就应该看起来是可以点击的) 
3. 如果用户完成一项任务需要复杂的操作,重新思考你的设计!!!

容忍错误

1. 只允许有意义的操作(适当禁用一些按钮) 
2. 尽量减少不可回退的操作 
3. 允许回退(undo)比使用确定对话框更好(实际上,应该尽量少用确定对话框,它对用户是一种干扰)如果错误是可能发生的,那它就一定会发生。

设计的考量

1.屏幕的物理尺寸 
2.屏幕密度 
3. 屏幕的方向(竖向和横向) 
4.主要的UI交互方式(触屏还是使用D-pad/trackball) 
5.软键盘还是物理键盘
6.了解不同设备之间的相异之处是非常重要的! 
7.阅读CDD,学习设备可能差异的地方 
8.了解屏幕尺寸和密度分类
 

响应的灵敏性(Designing for Responsiveness)

应用程序响应不够灵敏的地方包括——反映迟钝,挂起或冻结很长时间,或者需要花费很长的时间来处理输入。
在 Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应 (ANR:Application Not Responding)对话框。
什么引发了ANR:在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:
1:在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
2:BroadcastReceiver在10秒内没有执行完毕

如何避免ANR

运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume()) 里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请 求的方式)来完成。

增强响应灵敏性

一般来说,在应用程序里,100到200ms是用户能感知阻滞的时间阈值。这里有一些额外的技巧来避免ANR,并有助于让你的应用程序看起来有响应性。
1:如果你的应用程序为响应用户输入正在后台工作的话,可以显示工作的进度(ProgressBar和ProgressDialog对这种情况来说很有用)。
2:特别是游戏,在子线程里做移动的计算。
3:如果你的应用程序有一个耗时的初始化过程的话,考虑可以显示一个Splash Screen或者快速显示主画面并异步来填充这些信息。在这两种情况下,你都应该显示正在进行的进度,以免用户认为应用程序被冻结了。
简介:即使你的应用程序是快速且响应灵敏 的,但一些设计仍然会给用户造成问题——与其它应用程序或对话框未事先计划的交互,意外的数据丢失,意料之外的阻塞等等。简而言之,你应该竭尽全力去开发一个与系统和其它应用程序流畅交互的应用程序。

常见的流畅性问题:

1:一个应用程序的后台处理——例如,一个Service或者BroadcastReceiver—— 弹出一个对话框来响应一些事件。这可能看起来没啥大碍,然而,当你的应用程序运行在真机上时,有可能你的应用程序在没有获得用户焦点时后台处理显示了一个对话框。因此,可能会出现在活跃的应用程序后方显示了你的应用程序的对话框,或者从当前应用程序 夺取焦点显示了一个对话框,而不管当前用户正在做什么(例如,正在打电话)。 种情况就应该使用Notification来处理,而不是夺取焦点和打断用户。
2:另一个例子是未能正确实现Activity的onPause()和其它生命周期方法而造成意外丢失了状态或用户数据。

流畅性设计指南

1:别丢弃数据

如果用户在你的应用程序中正在编辑数据时,其它Activity出现了,这时,你的应用程序被杀死时可能丢失那些数据。
Android方式”是这样做的:能接收和编辑用户输入的Android应用程序应该重写onSaveInstanceState()方法,并以恰当的方式保存它们的状态。 对于持久性的数据应该在onPause()方法里面保存。

2:不要暴露原始数据

暴露原始数据,要求其它应用程序能够理解你的数据的格式;如果你变更了格式,那么,你将破坏那些没有进行同步更新的应用程序。
“Android方式”是创建一个ContentProvider,以一种清晰的、深思熟虑的和可维护的API方式暴露你的数据给其它应用程序。使用ContentProvider,就好像是插入Java接口来分离和组装两片高耦合的代码。这意味着你可以修改数据的内部格式,而不用修改由ContentProvider暴露的接口,这样,也不会影响其它应用程序。

3:不要打断用户

如果用户正在运行一个应用程序(例如,Phone程序),断定对用户操作的目的才是安全的。这也就是为什么必须避免创建Activity,而是直接在当前的Activity中响应用户的输入。
那就是说,不要在BroadcastReceiver或在后台运行的Service中调用callActivity()。这么做会中断当前运行的应用程序,并导致用户恼怒。也许更糟糕的是,你的Activity可能成为“按键强盗”,窃取了用户要提供给前一个Activity的输入。视乎你的应用程序所做的事情,这可能是个坏消息。
不选择在后台直接创建Activity UI,取而代之的是,应该使用NotificationManager来设置Notification。它们会出现在状态栏,并且用户可以在他空闲的时候点击它们,来查看你的应用程序向他显示了什么。
(注意,如果你的Activity已经在前台了,以上将不适用:这时,对于用户的输入,用户期望的是看到下一个Activity来响应。)

4:有太多事情要做?在线程里做

如果你的应用程序需要执行一些昂贵或耗时的计算的话,你应该尽可能地将它挪到线程里。这将阻止向用户显示可怕的“Application Not Responding”对话框。

5:不要让一个Activity超负荷

任何值得使用的应用程序都可能有几个不同的屏幕,当设计你的应用程序的时候,把你的应用程序看作是Activity对象的集合。从长远来看,这会使得你的代码更加方便维护。

6:扩展系统主题

当设计你的UI时,你应该尽量避免太多自己的主题。相反的,使用同一个主题。你可以重写或扩展你需要的主题部分,但至少在与其它应用程序相同的UI基础上开始。

7:设计你的UI可以应付多屏幕分辨率

不同的Android设备可能支持不同的屏幕分辨率,应确保你的布局和图片能足够灵活地在不同的设备屏幕上正常显示。

8:假设网络很慢

你应该按照最小化的网络访问和带宽来编写你的代码。

9:不要假定触摸屏或键盘

创建应用程序的时候,不要假定特定的键盘布局——除非你真的想限定你的应用程序只运行在某些设备上。

10:节省设备电池

如何让你的应用程序最小化的占用处理器,归根结底还是要写高效代码。为了减少无线的电量消耗,确保对错误条件进行正确的处理,并只获取你要的东西。
视频配套PPT,视频地址【 Android4开发入门经典独家视频课程
11
15
分享到:
评论
1 楼 tag13346 2012-07-24  
看来手机开发确实是门学问,和很多常识都是反的

相关推荐

Global site tag (gtag.js) - Google Analytics