如果你正在以“服务器”方式思维编写手机应用,那么你做错了

来源:互联网 发布:工商银行网络助手 编辑:程序博客网 时间:2024/04/29 15:28

如果你正在以“服务器”方式思维编写手机应用,那么你做错了

英文原文:If You're Programming A Cell Phone Like A Server You're Doing It Wrong

标签: <无>
286人收藏此文章, 我要收藏赵勇奎 推荐于 24天前 (共 15 段, 翻译完成于 10-10) (32评) 
参与翻译(3人)
bigtiger02, lwei, 纳兰融雪
仅中文 | 中英文对照 | 仅英文 | 打印此文章

电量对于手机来说就像沙漠中的水一样。它代表了生命。如果你把数据中心服务器上的朴素的编程技巧应用到手机上,你的手机会被“渴”死。

这一点已经被Reto Meier活灵活现的展示了,他是Android开发者关系维护团队的技术带头人,下面是其一系列非凡的教学视频:

  • DevBytes: Efficient Data Transfers - Understanding the Cell Radio
  • DevBytes: Efficient Data Transfers - Analyzing Your Transfer Profile
  • DevBytes: Efficient Data Transfers - Effective Prefetching
  • DevBytes: Efficient Data Transfers - Batching, Bundling, and SyncAdapters

之所以说它们是非凡的,是因为它们简短,且切中要害,充满了有用的想法和技巧。尽管Android有着独特的目标,上面目录中所列的教程仍具有通用意义。

lwei
lwei
翻译于 22天前

4人顶

 翻译的不错哦!

下面举例说明服务器编程和手机编程的区别,在服务器环境中,从一个服务器上拷贝一个文件到另一个服务器上通常需要一到两个管道。从一个文件描述符中读取一块数据,然后把它写入到另一个文件描述符中。这是一个同步的过程。你可能会在数据块大小和其它一些技巧上费点儿脑细胞,但那都是基本的。在手机上使用这种朴素而自然的“吸水”式逻辑却是错误的,它是一个Little Cookie 的过程,我们后面会讲到。问题就在于它吸干了手机电池。为什么? 因为手机无线信号装置将被迫持续工作。这又是为什么? 等会儿你会了解到更多,但是你需要做的是通过分批和正确的规划信息传输来最小化无线信号的使用。注意,你已经不在堪萨斯州境内了哦。 

这将把我们引向...

lwei
lwei
翻译于 22天前

3人顶

 翻译的不错哦!

核心想法: 手机中的无线通信最耗费手机电池的电量。每次你发送数据时,无论数据有多小,无线通信都会被启动20-30秒。所以你每一个决定都应当基于最小化无线通信启动次数这一初衷。通过改变你的app处理数据传输的方式,可以极大地提高电池使用时间。当用户需要获取他们的数据时,窍门就是在用户体验和数据传输之间做出平衡,同时使得电量损耗最小。app要想获得这种平衡,可以把重复和间断的数据传输捆绑在一起,然后一次性的主动的预先获取那些间断的传输数据。

lwei
lwei
翻译于 22天前

2人顶

 翻译的不错哦!

手机无线通信如何工作?

为了最小化无线通信来减少电量的损耗,首先你的了解手机无线通信是如何工作的。视频已经清楚的解析了手机通信的全部过程,如下为其中的一些要点:

  • 手机无线通信是被一个试图平衡低延迟和更长的电池寿命的状态机控制的。手机无线通信不会永远保持一个状态,它将进入不同的状态作为延长电池寿命的一种手段,但是如果要通过无线电发送数据则必须要切换到全功率状态。
  • 首先无线通信处于待机模式,该模式下电量消耗最低,直到一个应用启动了数据传输。
  • 要发送数据无线通信需要切换到全功率模式,这个过程到发送数据前需要大约2秒的时间。无线通信将在全功率模式下保持一段时间以防止更多数据需要被传输。这样它就避免了加速到全功率状态的时间开销。状态切换本身就是一个显著的电量消耗,因此需要最小化。
  • 如果在接下来5-10秒时间内没有任何数据传输,通信状态将会切换到一个中间额低功耗状态,这个状态它将使用更少的电量并且转换到全功率状态所需时间也更短。
  • 如果在接下来的30~60秒内任然没有任何数据传输,通信状态将会回退到待机状态。
  • 确切的延迟和尾时间因运营商、网络和设备而异。
bigtiger02
bigtiger02
翻译于 21天前

3人顶

 翻译的不错哦!

很明显传输数据有两种模型(如果你天真的只知道在手机上发送数据,那你没救了):

  • Big Cookie Model: 尽可能的对下载进行调度,最大限度的减少传输次数,最大化利用带宽。
  • Little Cookie Model: 传输数据尽可能的小并频繁的进行数据交互。

那种方式更好?Big Cookie. Little Cookie 频繁大量的使用无线通信。每次数据传输后,无线通信保持5秒的全功率状态,随后在回到待机状态前,将保持10~60秒的低功率状态。所以频繁发送小量数据会大量消耗电量。比如每15秒发送一次分析数据和用户断续的点击链接,其结果将可能导致持续保持无线通信状态。所以不要那样做。

bigtiger02
bigtiger02
翻译于 21天前

3人顶

 翻译的不错哦!

你的app应该做些什么?

了解手机状态机的好处就是如果你了解它,那么你可以在应用延迟策略和电量使用之间做出权衡。这个视频讲述了大量有关权衡的技术:

  • 最小化无线状态转换次数
  • 根据你应用电量使用情况做出判断
    • 通过如下方式生成图表:Logcat logging/应用资源优化/DDMS中的网络使用统计
  • 分析电池使用效率图表:
    • 寻找电量转移规律。这将导致无线通信的使用和电量消耗。更新周期越短,电量损耗越大。
    • 从图表中的找出短小或持续时间短的请求片段,这些请求片段可以被一起发送或预取。
  • 为接下来2-5分钟预取数据(1-5mb)
    • 这样做将会降低延迟并提高电池性能。通过下载所有数据用户很可能只需要一次请求而不是单一满负载连接,这样明显减小了无线通信使用次数。
    • 最大的挑战就是要搞清楚什么需要下载和什么时候不需要在用不到的数据下载上浪费电量。
    • 3G网络下,你可以在6秒内预取到足够的2-5分钟内应用需要用到的用户的会话数据,数据大小大约为1-5mb。如果数据在当前会话中有50%的机率不会使用到,那么数据不匹配的成本将会使节省的潜在价值大打折扣。
    • 并不是所有网络都是以相同的速率传输数据,所以需要在预取数据和网络效率上做出平衡。根据每个网络的传输速度和开销情况必须必须增加或减小预取缓存的大小。在速度更快的4G网络上,显然预取更多用户的数据电量消耗也更大。
    • 当手机无线处于激活状态时数据传输更有效。所以如果一个时间敏感传输被初始化了,通过立即传输数据来抢占利用这一状态(译注),任何数据传输需要在几分钟之内被执行。
    • 例如,如果用户需要阅读一片文章,这是一个预取用户接下来几分钟内需要阅读的其他内容的好时机。
    • 对于一个音乐播放器,只需要在缓冲区保持一首或以上的正在播放的歌曲,而不需要下载一整张专辑,因为很有可能用户根本不会听。
    • 对于新闻阅读器,最幼稚的方式是只下载顶层新闻和缩略图,这将使得无线通信一直处于忙碌状态。相反,你应该下载第一组新闻的头条、缩略图和文章内容,并稍候获取另一个批次的新闻。你可以尝试无论深度优先或广度优先策略,更好的办法是相信科学。保持追踪你用户和他们朋友所阅读的东西来预测他们可能阅读的新闻,你应该预取这些数据。或者你可以预取所有的东西,如果数据从来都不会用到的话那这开销太贵了。
    • 当电池寿命和带宽不是非常重要的时候(比如充电时),根据使用设备状态来调度下载。
    • 根据用户当前的活动来修改预取的策略。当应用被打开时和用户任然停留在某个界面时,应该预取更多的数据。
    • 一般来说,当应用程序处于后台时,不要预取数据。
    • 不要延迟应用启动,不要使用初始界面。在后台并发的预取数据来最大程度减少应用启动等待时间。
    • 如有可能,使用HTTP实时流,它将一次性传输数据,不同于连续流(它将使得无线通信一直保持激活状态)。
    • 批量捆绑进行所有非实时敏感的数据传输。
    • 在下个实时敏感操作发生时一次性批量传输数据。
    • 如果必须传送重复事件,随机它的周期性。
    • 如果一个操作对时间不敏感,比如上传图片,等待30秒可能会更好,万一另一个图片或数据也需要上传的话,可以一起批量处理。(详见SyncAdapter)
  • 消除客户端轮询
    • 使用Google Cloud Messaging。当有数据需要发送时候数据只会发送到你的手机设备上,因此没有轮询循环。它(Google Cloud Messaging)可以提供更低的延迟和更好的电量使用。
  • 降低数据传输的大小和频率
  • 使用刷新按钮
  • 根据应用使用降低更新频率
  • 创建一个批处理队列,你可以向队列添加容忍延迟的数据传输。下次你执行一个需求传输时,你也可以传输队列中的所有数据。如果应用在数据传输前关闭,可能发生数据丢失。解决办法是将数据保存到本地数据库,并从数据库查询需要传输的数据,应用关闭后数据库中的数据并不会丢失。Android中有一个叫做SyncAdapter 的东西可以用来来简化这上述过程。它是一个最佳实践。
bigtiger02
bigtiger02
翻译于 6天前

7人顶

 翻译的不错哦!

这些视频对所有这些都做了更为详细的介绍,尤其是SyncAdapter,所以值得好好看看。

这些视频把之前尚未讲清楚的事情都说清楚了: 在基于无线通信的手机设备上进行编程是一个特殊的领域,要想把它做好需要特定的知识和技巧。如果你一直想知道为什么app那么耗电,而电池总是没有想象的那么耐用,现在都可以轻松了解了。

lwei
lwei
翻译于 22天前

1人顶

 翻译的不错哦!

来自评论的内容

iOS7 说明

Plorkyeran: iOS最终在 iOS 7 中添加了后台数据获取,但却被严格限制了(操作系统决定应用什么时候去获取,而不是应用本身决定,实际使用中它可能会和一天一次一样少)。除此之外,仅有有限的几种类别的应用可以后台工作(诸如音乐播放器,voip应用,和位置跟踪器),事实上,他们拒绝那些声称有豁免权而实际上没有的应用。

dzamir: 事实上 iOS 7 使用本文描述的相同策略:它同时唤醒需要后台下载的所有应用以最小化无线功能的打开时间。

纳兰融雪
纳兰融雪
翻译于 15天前

1人顶

 翻译的不错哦!

担心电量使用情况是不是为时尚早?

miratrix: DCH(全功率状态)和PCH(最低功率、寻呼等待状态)之间(的电量使用,译注)相差了几个数量级。上次我测试的时候,在~3.7V电压下,无线通信在两种状态下的电量使用分别是:~100mA 和 ~1mA。所以,这并不是几分钟电池寿命的事情,而是相当于很多个小时的待机状态啊。用户通常都不喜欢刚充满电的手机一下就没电了。

我曾经看到过一些应用做过的疯狂的事情,这些事情对于电量有着显著的消耗。一个很流行的Android天气时钟小部件每分钟更新部件上的分钟数字,每15分钟(使用了GPS和无线通信)更新天气信息,这种行为轻而易举的使得手机原本可以待机几天的电池寿命缩短到不足8个小时。

bigtiger02
bigtiger02
翻译于 6天前

3人顶

 翻译的不错哦!

我不认为每个应用都要基于最小化唤醒全功率状态原则来做出决定, 但是在另一方面,所有的开发者至少应该试图尽可能多的了解他们所工作的平台,这样他们就会知道怎样在增加的每个功能上做出权衡。

kintamanimatt: 尊重已知限制和工作的最佳方式是绝不要过早的进行优化。如果你知道使用手机无线通信是一个非常昂贵的电量消耗,那么忽略这一原则是一件非常愚蠢的事情。这不是过早优化的问题,如果你一开始就知道问题出在哪里。这一性能问题是如此普遍以至于android团队将他们放在视频里面进行了介绍。

bigtiger02
bigtiger02
翻译于 6天前

3人顶

 翻译的不错哦!

手机无线通信将会快速的消耗手机电量,很有可能和屏幕电量消耗一样多。如果你想要了解无线通信电量消耗到底有多昂贵,先禁用快速休眠,打开一个OpenVPN连接,这将会使得你的手机无线通信一直处于一个较高的功率状态,这和一些流氓应用的做法非常相似,你会(意料之中)看到手机电量消耗的非常快。

写的不好的应用将会缩短几个小时的电池寿命,而不是几分钟。

kevin_nisbet: 我只想从网络运营商的角度来看待这件事情。我在一个移动运营商工作,不得不一些和与设计不良的应用有关网络问题打交道。在这个问题上,我同意kintamanimatt 的观点,这确实不是过早优化的问题,你必须得知道你所做的事情要付出的代价。对于目前所有的天真的应用开发人员来说,这确实是一个令人难以置信的资源成本开销,它使得无线通信接口总是保持连接状态。

bigtiger02
bigtiger02
翻译于 6天前

3人顶

 翻译的不错哦!

1、关于每分钟轮询服务器实际上我们曾经给一个客户寄过一个超过100,000美元的发票,因为他们有一个特别差劲的应用,每分钟都去轮询服务器,而且这只是一个内部应用,只有办公室内的几百人在使用。轮询引发了他们公司手机网页站点的持续阻塞。这实际上破坏了他们的办公室附近的蜂窝覆盖,并对同一地区的所有其他用户造成的问题。最后,我们说我们可以帮助你修复应用,你可以选择支付发票来升级办公室的网络覆盖,或者不要使用我们的网络。在这个例子中,我们帮助他们修复了应用,其实在某些东西发生改变的时候才需要与服务器进行交互(服务器推送变化),实际上这很容易做到。这和编写一个组件内部循环来减小运行时几微秒这类过早优化不是同一类型的事情,并且它使得软件更加健壮,无论在哪里使用效果都很好。
bigtiger02
bigtiger02
翻译于 6天前

2人顶

 翻译的不错哦!

2、同步网络访问这点已经好几次成为了我们的祸根。如果你编写一个网络访问,不仅仅是每15分钟运行一次,而是所有设备在相同时间都去访问。当我们的无线网络崩溃时,你们开始愤怒、抓狂。所有设备同一时刻被唤醒,转换到高功率状态,请求数据,但同一时刻网络只能处理那么多(的请求)。有趣的是,你自己进行测试,并没有发现任何异常,但是当你应用发布之后,你可能发现30%的检查失败是由于同一原因引起的,并且努力试图弄清楚它的原因。对于任何一个考虑这个问题的人,我们的答案是,网络访问应该增大容量,但是最终客户需要为网络建设买单。

3、设备供应商出于保护客户的利益的目的会关心网络使用频率高的应用将会发生什么情况。我们的网络上曾经有一个将所有拒绝代码当作重试原因的应用,这导致每次应用运行将会一遍又一遍重复上传数据,直接导致客户需要支付数千美元昂贵的数据使用费。最终设备供应商从商店下架了该应用。

bigtiger02
bigtiger02
翻译于 6天前

2人顶

 翻译的不错哦!

现在你的感觉如何?你不得不为什么你应该被继续允许销售你的产品向不仅仅是设备供应商而且还包括发现问题的受害者进行申辩,证实你已经修复了这一问题,通过我们的官方测试来证明你确实修复了它,才会允许你再次销售。这并不和修复bugs一样简单,实际上在产品下架的这几个月中,你失去依靠这款软件赚钱的能力。

当所有客户由于使用了你的应用而收到5000美元的账单的时候,你认为应用的商店评分会是怎样的?

bigtiger02
bigtiger02
翻译于 6天前

2人顶

 翻译的不错哦!

现在的问题是,应当有一种更好的方式,我愿意从移动提供商中看到更多,将这从非常愚鲁转变为十足明智。在手机 API 中,如果我需要去做后台更新,我应当能够向操作系统注册,并说,我有一个更新任务要做,在接下来的15分钟内,当您有活动的网络连接时告诉我。您的手机进入高强度的无线网络连接状态,同时欺骗,现在您所有的后台更新现在同时开始。已经有我们的推送 API ,要发送通知,仅当一个更新需求快要完成时进行再交互。如果您正在用的 API,是为移动设备设计的,同时做许多这样的您无需知道用户帐户的网络工作,对一无所知的开发者来说,这么做比碰运气更好。

-- * 本文中我的观点全部是我的个人观点,和我的雇主意见无关。

纳兰融雪
纳兰融雪
翻译于 15天前

1人顶

 翻译的不错哦!

原创粉丝点击