第一部分:开发前的准备-第七章 怎样做出一个好应用

第7章 怎样做出一个好应用

本章从5个方面来讲解一个做出好应用需要注意哪些地方,它们包括

1. 易于操作

2. 性能优化

3. 即时响应

4. 无缝流畅

5. 安全

7.1 易于操作

在设计应用的时候,我们应该热爱极简主义,简单就是好的,对于很多用户来说,复杂的东西并不受欢迎。并且许多Android用户有残疾,需要给他们提供不同的方式来与Android设备进行交互。

能一步到位的操作,就不要弄成几个步骤,举个例子如果你玩过魔兽世界的话,你会发现随着版本的更新技能是越来越少的而不是越来越多,也许你会看到新出来的几个技能,但是暴雪省去的技能是新增的几倍,例如法师传送整合为一个技能,去掉了火焰防护,冰霜防御,改成一个双重吸收的盾,这样简化操作当然是玩家们乐于接受的。下面我给大家举一个工作上的例子:

    某日,领导要求我们的游戏中需要整合微博的功能,包括腾讯,新浪,人人,开心。要求只需要实现发送文字和图片的功能即可,其他不需要。这个功能由我独立完成。

最开始跟领导讨论界面,我们讨论的结果如下:

1.在“选项”对话框中添加一个“微博”按钮。这个按钮用来授权

2.另外增加一个信息按钮用来发布微博

当时我并没有多想,因为我必须先把功能实现完毕后在考虑界面上的问题。然后开始使用上面4个平台提供的SDK来实现我们的需求。在根据SDK实现我们功能要求的时候,我发现有个SDK是发布文字和图片提供同一个接口,而有的SDK则是发布文字提供一个接口,发布图片提供一个接口。于是我需要2次开发SDK自己写一个统一的接口来封装文字和图片。逻辑很简单,如果没有图片或者用户想取消发送图片的话就只发文字,否则同时发送图片和文字。过了一段时间后功能都实现了,开始整合到项目中,添加进界面后开始用户体验测试,我发现这真的很繁琐,如果你需要发一个微博,需要如下步骤:

点击“选项”->“微博”->“某微博”->授权成功后点击“返回”按钮到主界面->点击“信息”按钮弹出发送界面->点击“发送”

一个简单的发布微博的操作需要6个步骤,你会发现如此的繁琐,用户体验很不好。于是我发现网站整合微博平台的时候都是一键发布,就是说授权和发布都是一个按钮,逻辑如果你没有授权就先授权成功后自动跳转发布界面,如果你已经授权就直接显示发布界面。这样如果需要发送微博的话步骤如下:

点击“选项”->“微博”->“某微博一键发布” ->点击“发送”

这样的话我们减少了两个操作步骤并且移除一个“信息”按钮。接下来又需要二次开发SDK,因为有些SDK没一键发布要自己写逻辑。好了,至此可能大家认为可能不能在简化操作了。但事实并非如此,和领导沟通后发现还可以简化,因为大家经常使用自己喜欢一个微博来发布,于是我们在“微博”对话框中的每个微博后加入了“设置为默认”。如果你点击后这个微博就会成为默认微博,并且与“选项”按钮同级别。下面看下我们简化后的操作步骤:

点击“被设置成默认的某微博”->点击“发送”

这样的话,我们操作就只有2步就能完成了。这样我们从最开始的6个步骤简化到2个步骤,以用户角度考虑的你是不是更喜欢这种操作方式呢。这只是举一个例子让读者明白,其实简单的操作是很受欢迎的,我们应该尽可能的简化操作而不是使操作复杂化。

7.2 性能优化

我们要知道一个Android应用程序将运行在一个有限的计算能力和存储,以及有限的电池寿命的移动设备上。你可能在做完项目后想继续优化你的应用程序,即使它已经足够快了。对于用户来说

电池寿命是很重要的,如果你的应用很容易就消耗完他们的电池,那么这就是一个减分的用户体验。请注意,虽然本章主要包括微型的优化。选择合适的算法和数据结构应该永远是你的优先级。

1. 慎重的优化

本章是特指android上的优化,因此它假定你已经分析出什么代码需要优化,并假定你有一个方法来测量代码的好坏。所以我们把逻辑上的优化排除在外,只用来优化android。

关于逻辑上的优化,希望你能通读Josh Bloch的Effective Java。

首先我们面临的问题就是我们的应用要保证能在多种硬件平台下运行。因为这些不同的设备会让你可能遇到不同的系统版本,不同的CPU运行速度,这些最终都需要在VM(虚拟机)上运行。

并且是否使用Jit(just in time,即时编译技术)会有巨大的区别。如果你想知道你的应用程序如何在一个给定的设备上执行,那么你需要在该设备上测试。

2. 避免创建不必要的对象

创建对象永远不是免费的。虽然有GC这种机制在,但分配内存付出的代价永远都是大于不分配内存的。如果在用户界面循环的分配对象,你将导致GC在某个周期内强制回收垃圾,这样会让用户体验到一种“打嗝”的感觉。虽然Android2.3引入了并发收集器的帮助,但应尽量避免不必要的工作。

因此,我们应该尽量避免创建实例对象。下面有一些例子也许能帮到你:

(1)如果你有一个方法返回一个String,并且你知道这个结果总是要追加到StringBuffer 中,那你就可以直接在追加的地方调用这个方法,而不是去创建一个临时对象。

(2)当从一组输入的数据中提取字符串时,使用原始数据的substring()方法返回你需要的字符串,而不是去创建一个副本。

有些人是把多维数组切成一维数组,一个int[]数组要比Interger[]数组要更好一点。一般来说,我们避免少创建临时对象。因为更少的创建对象意思就是让垃圾回收不频繁,这对用户体验有直接的影响。

3. 某些理解的性能误区

(1)如果你不需要访问对象的属性(值域),就让你的方法静态。调用速度将提高约15%-20%的。

(2)避免内部使用get或者set:

例如本地C++语言,一般会使用get方式“i= getCount()”,而不使用直接变量赋值的方法“i=mCount”。在C++上这是一个很好的习惯,因为编辑器会内联访问。但是在android上这是一

个不好的做法。虚拟方法的调用是昂贵的,他的代价超过了实例字段查找。虽然面向对象思想中使用get和set是很好的习惯,但是在一个类中调用本类的变量我们应该直接使用变量,而不需要使用get方法。

4. 对于常量使用Static Final

常量我们应该写在类的最上面例如:

static int intVal = 42;
static String strVal = "Hello, world!";

编译器在生成类的时候,会调用初始化方法<clinit>,当这个类第一次被使用时。就会调用该方法,并且等待被引用。但这对于常量来说并不是最好的一次方法,更好的一种方法是:

static final int intVal = 42;
static final String strVal = "Hello, world!";

加上final关键字的话,编译器不会调用<clinit>方法,他直接被打包到.dex的静态字段中。

5. 使用加强的循环语法

加强的循环其实就是for-each循环,内部就是实现java中的Iterable 接口,然后开始迭代,它的效率是普通for循环的三倍。

下面我们来看看遍历一个数组的几种选择:

 

  
 static class Foo {

        int mSplat;

    }

    Foo[] mArray = ...


    public void zero() {

        int sum = 0;

        for (int i = 0; i < mArray.length; ++i) {

            sum += mArray[i].mSplat;

        }

    }


    public void one() {

        int sum = 0;

        Foo[] localArray = mArray;

        int len = localArray.length;


        for (int i = 0; i < len; ++i) {

            sum += localArray[i].mSplat;

        }

    }


    public void two() {

        int sum = 0;

        for (Foo a : mArray) {

            sum += a.mSplat;

        }

    }

zero()是最慢的,因为JIT不能吧这个数组的长度变量变成常量,每次循环都需要引用变量

one()比zero快一些,使用局部变量就避免的查找,但这只能提供"数组长度"这一个性能上的好处。

two() 最优的,使用了java1.5中的for each循环。不仅仅是优化访问数组长度,还提高的循环效率。语法上也更精简。

6. 慎重的使用Float

在android上,float的速度比integer要慢两倍。但是float和double在速度上没什么差别,只是double占用的空间是float的两倍

7. 了解和使用库(Libraries)

合理使用库文件中的方法,是提高效率的一种方法,虽然我们都喜欢用自己写的东西,但是有些权威性的东西我们还是可以拿来主义的,例如使用System.arraycopy来copy的速度比你手动循环要快9倍

8. 慎重的使用本地方法

本地代码不一定比java更有效,除非必要,我们尽量还是不要使用本地代码。例如JNI(JNI:Java本地接口。它定义了管理代码的方法并与本地代码互动,直接的说就是java与C/C++的互动。我们应该认真的了解一下j2se 6上的JNI。了解它的功能。更详细的信息可以访问Java官网)。

7.3 即时响应

一般来说我们写客户端都分为逻辑程序员和UI程序员。假设逻辑程序员用最优的算法,最好的数据结构,最易扩展的架构,那么这款应用在程序部分也只是完成了一半而已。因为后半部分在于UI程序员的发挥,也许你写的程序逻辑是世界上性能最好的,但由于UI程序员没有考虑到即时响应的问题,导致你的应用被用户抱怨,认为它很慢。其实有时候就是简单的异步处理就能解决这个问题,但UI程序员和逻辑程序员应该多沟通,这样才能避免出现“假死”的现象。一个很好的例子就是:某微博开放平台中Anndroid SDK例子中的代码,当你通过授权后,输入了文字并点击发送的时候,这里会卡住5-10秒,这样的用户体验完全是糟糕的,它并不是性能和逻辑上的问题,而仅仅是一个简单的异步UI处理就能搞定它。我们需要修改源码,当点击发送按钮的时候就关闭当前输入框,不用管它是否发送成功,那是异步线程要处理的事,它会使用接口返回结果让我们自行处理。

在android中,系统会检测应用程序,如果一段时间内它没有响应,就会给用户显示一个对话框,它被叫做 Application Not Responding (ANR)对话框,如图7-1所示。用户可以选择等待或者强制关闭,但这个对话框用户应该不想经常看到。如果一个应用不能响应用户输入,那么系统就会显示一个ANR。例如,如果应用程序在I/O操作(通常是访问网络)上被锁定了,那么主线程将不能处理用户输入事件。一段时间后,系统推断这个应用程序被冻结了,然后会显示一个ANR给用户,让用户来杀掉它。

一般是建议大家创建一个自己线程来处理比较耗时的操作,例如访问网络,初始化载入资源等,这样就不会出现ANR的情况,

 

图7-1 一个ANR 对话框的截图

 

1. 是什么原因引发的ANR?

以下这些情况会引发ANR:

(1)五秒内没有响应输入事件(例如按键,触摸屏)

(2)一个BroadcastReceiver在10秒内没有执行完。

2. 怎样避免ANR

正常情况下android应用程序是单线程执行的,这意味着你所有的工作都在这一个线程执行。在Activity声明周期的方法中,我们应该尽可能少的给它们安排工作。特别是网络或数据库的操作千万不要放在onCreate()和onResume()中,我们应该另起线程来执行它们,这样就能避免五秒情况产生的ANR。对于BroadcastReceivers我们也应该避免让他执行耗时的操作,因为BroadcastReceivers是定位于短时间通知事件,如果你需要长时间的操作。你可以考虑使用Android中的Service

3. 加强响应

一般来说100-200毫秒之间是可以接受的,如果200-400毫秒你就会感觉要延迟了,例如CS或者WOW这两种游戏如果在200-400毫秒之间你会明显的感觉到延迟,下面是两个很好的例子:

(1)如果你的应用在后台工作并相应用户输入,你可以使用进度条。例如计算一个子线程的进度,游戏中常用你可以使用进度条(ProgressBar 和ProgressDialog )。

(2)如果你的应用在初始化启动的时候比较费时,你可以考虑吧初始化工作异步处理,android主线程用来显示处理界面,如果他们放在一起,你会发现进游戏那会需要等待载入很久,这样用户会感觉你的应用很慢,你只要让用户知道,你不是卡住而是在载入资源就行了,所以你需要一个界面来展示给用户,让他明白

7.4 无缝流畅

即使你的应用是快速反应,某些设计决策仍然可以对用户造成的问题:例如其他应用程序或对话框的相互作用,数据的意外丢失,意外拦截,等等。总之,你应该努力开发一个应用程序让之与系统或其他应用程序无缝交互。一种常见的现象是,当一个应用程序的后台进程(例如一个service或broadcast receiver)弹出一个对话框用来响应一些事件。表面看起来这貌似是无害的行为,尤其是当你测试你的应用的时候,你可能很需要它。但实际上如果时不时的弹对话框给用户,这会导致用户越来越讨厌你的应用,然后删掉它。为了避免这种问题,你的应用应该使用Notification机制。使用通知的话,你的应用程序可以告诉用户事件已经发生了,它会显示在状态栏,而不是弹出对话框来强制中断用户。另外还有一个例子就是当一个开发者由于没有正确的理解Activity的生命周期而在onPause() 或其他方法中不慎丢失掉当前状态或者用户数据。这样同样会跟用户带来很不爽的体验。下面让我们来讨论下无缝流畅的问题。

1. 不要丢弃数据

请时刻记住android是一个移动平台。经常会发生一个Activity弹出到你应用的上方,例如一个来电,这时会调用onSaveInstanceState()和onPause()方法,用来保存你的一些数据。如果用户正在编辑数据然后突然出现另一个activity,那么你的应用可能会丢失数据,所以好的做法应该是在onSaveInstanceState()方法中适当的保存它的状态,以便于待会恢复。

一个处理的比较好的例子就是mail应用程序。如果用户正在撰写邮件,当另一个activity启动时,mail应用会保存正在撰写的邮件,它会自动保存为一个草稿。

2. 不要公开原始数据

一般很少有人穿内衣上街吧,我是说很少,不是说绝对没有一个,偶尔总有些特别人,但我们是普通人还是走大众路线吧。同样的道理我们应该尽量不要公开我们的原始数据,因为公开原始数据需要其他应用程序理解你的数据格式,如果你改变了格式,其他应用程序就使用不了了,因为它们不会自动更新在android中,我们推荐创建一个ContentProvider来公开你的数据给其他应用程序,以松耦合的方式,让你的两个模块完全分开,这意味着你可以在ContentProvider内部修改数据格式,而提供给外部的接口不变。

3. 不要打断用户

关于这一点,仍旧需要强调,不要轻易的调用startActivity()或者弹对话框,这样会强制中断用户,有可能使用户恼火。时刻注意能用Notification的地方就不要用其它方式。你可以使用NotificationManager来设置Notifications。

4. 不要重载一个单一的Activity屏幕

任何一个值得我们使用的应用程序都有几个不同的屏幕界面。当设计屏幕UI时,你应该考虑多个Activity来组合成整个界面UI。举个例子,例如一个简单游戏的界面设计,应该有几个部分组成,登录界面,菜单界面,游戏界面,每个界面其实都可以当成一个Activity。以后扩展起来也更方便

5. 扩展系统主题

外观和感觉要统一,这一点很重要。第二大篇中我们会讲到如何使用风格和主题,统一的风格很重要,并且要符合你的应用的感觉。如果要深入研究的话,可能要花点功夫。

6. 假设网络很慢

Android设备将提供多种网络连接方式。例如蜂窝网络,3G,wify,蓝牙等,有可能它们会很快,但有可能也有慢的情况发生,所以我们一般要假设网络很慢的情况下,用户体验是个什么感觉,即使网络很慢,你也应该即时做出响应,并提示用户是个什么情况,这样的体验对偶尔网速慢的用户来说是比较好的。

7. 请"爱护"电池

如果移动设备不断地插在墙上,它就不会感觉是个移动设备了。移动设备是电池供电。而最消耗电池的两大元凶就是处理器和无线电,这就是为什么我们总要让程序做尽可能少的工作,并少使用网络的原因。编写高效的代码,最大限度地减少你的应用程序真正使用的处理器时间量。尽量减少使用无线电功耗,确保优雅地处理错误。例如,如果操作网络失败了,不要一直重试网络操作,这样很耗电,
用户是非常聪明的:如果你的程序是耗电的,你的应用程序就等着被删吧。

7.5 安全

通常安全和性能是很难两全的,你安全上多考虑一些,性能上就会低一些,你性能上做的多一些,安全就会低一些,所以我们需要权衡我们的应用对于安全和性能的要求,例如类似银行的软件我们肯定要安全考虑的多的多,但如果是游戏,那性能的比例就要高一些。对于android来说,它提供了一些内置的安全机制,我们如果熟悉它的话,就能为我们省去不少工作。

7.5.1使用Dalvik虚拟机代码

比较底层的东西,如果你想在虚拟机上编程的话,可以考虑研究一下,并且在android上,Dalvik虚拟机并不是安全的。Dalvik可以用本机代码和android相互操作并且没有任何安全限制。考虑到移动设备上的存储空间有限,开发人员共同都希望建立模块化的应用程序,并使用动态类装载。但不应该使用动态类来加载没有通过验证的来源,如不安全的网络资源或外部存储,因为该代码能被修改,可能会包括一些恶意行为。

7.5.2使用本地代码

在一般情况下,我们鼓励开发人员使用Android SDK来开发大多数应用程序,而不是使用本地代码。因为本地代码生成的应用程序更复杂,更不可控,容易出现常见的内存错误,如缓冲区溢出。Android使用的是Linux内核,如果你要使用本机代码,那么熟悉Linux上开发中的安全问题会更好。Android和大多数Linux环境之间的一个重要的区别是Application Sandbox(沙箱)。在Android上,所有应用程序都运行于沙箱中,包括那些与本机编写的代码。如果熟悉Linux的开发人员肯定认为它是一个好办法,要知道,每个应用程序都被赋予一个唯一的UID非常有限的权限。你应该熟悉应用程序的权限,即使您正在使用本地代码。

7.5.3数据存储

1. 使用内部文件

默认情况下,内部存储上创建的文件仅能访问的应用程序创建的文件,这种保护措施是android提供的,对于大多数应用程序来说已经足够了。如果是想使用Context中的MODE_WORLD_WRITEABLE和 MODE_WORLD_READABLE 标志用于IPC(进程间通讯)的话就比较悲剧了。因为默认的内部存储不提供数据访问限制能力和控制能力,所以我们应该使用ContentProvider来动态授予读取权限。

2. 使用外部存储

外部储存设备(例如SD卡)上创建的文件,是全局可读可写的。由于外部存储设备能被也用户移除,并也能被任何应用程序修改,所以一个好的应用程序不应该使用外部存储设备存储敏感信息。

3. 使用Content Providers

ContentProviders提供了一个可以被限制在自己的应用程序的结构化存储机制或者提供一个入口允许其他应用程序访问。默认的,一个ContentProvider被其他应用程序导出使用。如果你不打算让其他应用程序访问你的ContentProvider。那么你可以在manifest文件中使用android:exported=false。当创建一个提供给其他应用程序导出的ContentProvider时,你能指定一个简单的权限(permission )用来读取和写入或者单独指定可读或可写。对于权限我们只要根据自己的应用程序需求来打开相应的权限,切忌不要把无关的其他权限都打开,这会带来不必要的麻烦。如果你需要使用一个ContentProvider来在我们开发的其他应用程序期间能共享,那么请使用 signature level permissions(第二篇的manifest文件中会详细讲述它的意思)签名权限,不需要用户确认,所以这个权限提供更好的用户体验和更多对ContentProvider的控制访问。

ContentProviders也能提供更多的颗粒级访问,在第二篇的manifest文件详解中会有 grantUriPermissions 节点是关于它的。当你访问一个ContentProvider,使用带参数的查询方法例如query(),update()和delete()来避免潜在的SQL Injection(SQL注入式攻击)。注意如果selection 在用户数据提交之间被建立了,使用参数化的方式是不够的。

7.5.4使用进程间通讯 (IPC)

一些android应用程序尝试使用传统的Linux技术(例如网络套接字和共享文件)实现IPC。谷歌官网是强烈建议使用android系统功能来实现IPC,例如Intents,Binders,Services和Receivers。android IPC机制允许你验证应用程序的身份。许多安全元素是通过IPC机制共享的。Broadcast Receivers,Activities,Services都在manifest中声明。如果IPC机制不打算被其他应用程序使用,那么请设置在manifest文件中的service节点设置android:exported属性为false。对于使用同样UID的并有多个进程的应用程序来说是非常有用的。注意Intent filters不应该被视为一种安全的功能,因为这个组件可以直接调用并且可能没有匹配的数据。

1. 使用intents

Intents是异步IPC首选的机制。根据您的应用需求,你可能会使用sendBroadcast()中,sendOrderedBroadcast()并传入intent。注意ordered broadcasts()能被一个容器完全消耗掉,所以它们可能不会被传递到所有应用程序。

2. 使用binder和AIDL接口

对于RPC-style的IPC来说Binders是首选的机制。

不要求接口的具体权限检查的情况下,最好是用接口的设计方式。Binders 在manifest中不能声明, 因为你不能直接用声明的权限到一个Binder中。Binders一般继承manifest中对于Service或者Activity实现的某些权限。如果需求提供一个访问控制的接口,使用checkCallingPermission()来验证调用者的Binder是否有一个必须的权限。如果由一个Service提供一个接口,并且如果你没有获得访问Service的权限那么bindService()可能会调用失败。如果是你自己的应用调用一个本地的接口,那么应该使用clearCallingIdentity(),它会对内部安全进行检查。

3. 使用BroadcastReceivers

BroadcastReceivers被用于处理通过intent发起的异步请求。默认的,receivers被导出并能被任意其他应用调用。如果你的BroadcastReceivers打算为其他应用程序使用,那么你可能想要应用安全的权限来接收,就请在manifest中它们使用<receiver>节点。

4. 使用Services

Services经常使用其他应用程序提供的功能。每一个service类在AndroidManifest.xml中必须有一致的声明。默认的,Services被导出并能被任意其他应用调用。Services通过在manifest中的<service>标签使用android:permission属性来保护自己。通过这种方式,其他应用程序在manifest 中将必须声明一致的<uses-permission>节点。

5. 使用Activities

Activities大部分经常用于提供核心的功能。默认的,如果Activities有一个intent filter或者binder声明,那么它们就能被导出并可以被其他应用程序调用。最好的方法是声明一个Receiver 或Service来处理IPC,因为这种模块化的方法能减少一些不必须要的暴露风险,比如你有些功能你并不想让其他应用使用。

7.5.5使用网络

1. 使用IP网络

Android上的网络和Linux 上是没有太多不同的。重点考虑的是确保敏感数据使用适当的协议,例如对于web流量使用。应该更倾向使用https而不是http,任何服务器都支持https,如移动设备经常连接到不固定的网络上,例如公共wify热点。

加密套接字级别的通信可以使用SSLSocket类来进行身份验证。鉴于Android设备经常使用不安全的WiFi无线网络,谷歌是大力鼓励所有应用程序使用安全的网络。

我们已经看到一些应用程序使用本地主机网络端口来处理敏感的IPC。这种做法是不太好的,因为这些接口容易被其他设备上的应用访问。相反,使用一个Android的IPC机制(如Service 和Binder)来验证是合适的,如Service 和Binder。

2. 使用电话网络

SMS(短信)是大多数android开发者频繁使用的协议。开发者应该记住这个协议主要是为user-to-user而设计的通讯协议。许多开发者没有意识到,SMS是没有加密的或者没有通过网络认证的。尤其是SMS的接收,有可能一个恶意的用户可能会发送SMS到你的应用程序,请不要小看SMS带来的影响,最好不要通过未经认证的SMS数据来执行敏感的命令。

7.5.6动态加载代码

对于从应用程序的Apk外部加载代码是强烈禁止的。由于代码注入或篡改的行为会大大增加了应用程序的危险性。它也增加了周围的版本管理和应用程序测试的复杂性。最后,它可能使其无法验证应用程序的行为,然后被禁止在某些环境中运行。如果你的应用程序是动态加载代码的,你要记住它和应用程序APK的安全权限一样并执行。

1. 使用WebView

由于WebView中可以包括HTML和JavaScript这样的网页内容,使用不当可导致常见的web安全问题。例如跨站点脚本攻击(JavaScript 注入)。Android包含一些机制,以减少这些潜在问题发生。

如果您的应用程序不需要直接在WebView中使用的JavaScript,那么请不要调用setJavaScriptEnabled()。默认情况下,WebView中是不执行JavaScript的

使用WebView.addJavaScriptInterface()应特别小心,因为它允许JavaScript 调用为android应用程序正常保留的一些操作。只有在所有输入来源是值得信赖的情况下才暴露,通常建议是只有你Apk内部包含的JavaScript才暴露给addJavaScriptInterface()。

不信任的信息请通过https下载而不是http。就算你只连接一个单一的网站也容易受到攻击。但即使使用https也不是绝对的安全,如果APK中默认暴露了WebView.addJavaScriptInterface(),就会有不安全隐患。如果您的应用程序访问与WebView中的敏感数据,你可能想使用的clearCache()方法来删除本地存储的任何文件。如服务器没有headers 就表示应用程序应该不缓存具体的内容(例如没有http开头的域名)

7.5.7执行输入验证

无论在什么平台中,不健壮的输入验证经常会导致应用程序出现安全的问题。Android平台中有一些对策来让你尽量减少处理应用程序的输入验证问题,请尽量使用 Android SDK

如果您正在使用本机代码,然后从文件中读取的任意数据或者通过网络获得数据都有可能导致安全的问题。最常见的问题就是缓冲区溢出错误。Android本身提供一些技术来减少这些错误的发生,但还是没有从根本上解决问题,只是预防而已。如JavaScript和SQL语言也有输入验证问题,如转义字符和脚本注入。如果你正在使用数据查询刚好这个数据被提交到SQL数据库或者Content Provider, 就会导致SQL注入问题。最好使用参数化查询,以后我们会在ContentProviders详细讨论的。

如果您不能使用上面的安全功能,就请使用结构良好的数据格式,并核实该数据符合预期的格式。但这些技术在实践中很容易出错。

7.6 本章小结

本章,我们讲解了

1,易于操作

2,性能优化

3,即时响应

4,无缝流畅

5,安全

这章的内容对于一个开发者来说是比较重要的,因为笔者鼓励大家做精致的应用,而不是粗制滥造。这点我们应该向国外学习,打造精品,注意细节。虽然有很多客观原因会影响我们,但笔者还是希望每一个开发者能认真花心思做一个好应用!

本文来自jy02432443,QQ78117253。转载请保留出处,并保留追究法律责任的权利

posted @ 2013-11-18 20:13  jy02432443  阅读(1160)  评论(0编辑  收藏  举报