Android性能模式篇之智能的工作计划(译)

KenSteed 8年前
   <p>随着需求和业务的发展,越来越多的apps需要去异步执行各种各样的任务,有些任务是用户去执行的,而有些任务则是apps自身需要去执行,这些任务的使用场景有如下示例:</p>    <ul>     <li>更新网络资源</li>     <li>下载信息</li>     <li>更新后台任务</li>     <li>处理系统服务的回调</li>    </ul>    <p>如何智能化的去处理这项工作,是至关重要的,如果处理方式得当的话,不仅可以提高你的应用性能,还可以减轻系统的压力,例如通过减少你的应用耗电量,来达到省电的效果。</p>    <p>于是,针对这一需求,<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>应运而生。</p>    <p>目前Android系统已经提供了几种APIs来让你的app安排后台任务,但是我们建议优先选择<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a> ,因为<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a> API不仅可以选择一个合适的时机去执行任务,提高app和系统的性能。.<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>还具有高度的扩展性和适用性。你可以通过它来执行一个简单的任务,如清除缓存,也可以通过它来执行复杂的任务,如同步你的数据库到云端。</p>    <p>除了<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a> ,还有其他一些类似的APIs去帮助安排你的工作计划,它们包括:</p>    <ul>     <li><a href="/misc/goto?guid=4959675985085383233" rel="external">AlarmManager</a></li>     <li><a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a></li>     <li><a href="/misc/goto?guid=4959675985263538733" rel="external">GCM NETwork Manager</a></li>     <li><a href="/misc/goto?guid=4959675985350863861" rel="external">SyncAdapter</a></li>     <li><a href="/misc/goto?guid=4959675985350863861" rel="external">Additional Facilities</a></li>    </ul>    <p>本篇文章简要介绍了<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>和其他API,可以帮助你的应用程序优雅的去安排你的工作计划。</p>    <h2>Android Framework JobScheduler</h2>    <p><a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>是由<strong>Android</strong>系统框架所提供,它被用来执行任务或者安排工作计划,目前<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>只能在<strong>Android 5.0</strong>以上的版本才可以使用,并且一直在不断的完善中,尤其是,在最新的<strong>Android N</strong>版本中增加了一个新的功能,在<a href="/misc/goto?guid=4959675985471961691" rel="external">ContentProvider</a><br> 发生改变时触发你的工作计划。</p>    <p>由于<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>是在<strong>Android</strong>系统框架内实现的,所以当apps选择使用<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>时,它可以通过收集一切有利于安排工作计划和执行任务的有关信息,更好的去完成它的工作。这种方式的批量作业执行允许设备进入和停留在休眠状态更长的时间,保护电池寿命。</p>    <p>通过注册<code>jobs</code>来使用<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>,并指定它对网络和时间的要求,然后<strong>Android</strong>系统会优雅地安排工作在适当的时间执行,同时,它也将执行必要的工作在遵循<a href="/misc/goto?guid=4959675985589162190" rel="external">Doze and App Standby</a>的限制前提下,另外,<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>也提供了许多方法来定义工作的执行情况。</p>    <p>如果你的应用程序的目标是<strong>Android 5(API Level 21)</strong>以上,我们建议您使用<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>执行后台任务。关于<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>的更多信息,见其<a href="/misc/goto?guid=4958860265564001864" rel="external">API参考文档</a>。</p>    <h2>AlarmManager</h2>    <p><a href="/misc/goto?guid=4959675985085383233" rel="external">AlarmManager</a> API是<strong>Android</strong> 系统框架提供的另一种选择,用来安排你的工作计划。它的使用场景,一般是app需要在一个特定的时间发布一个通知或在一个特定的时间内发出一个指示信息。</p>    <p>如果你的需求仅仅是执行在一个特定时间的任务,而不考虑其他方面的话,你可以使用<a href="/misc/goto?guid=4959675985085383233" rel="external">AlarmManager</a>。<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>则更加灵活,你可以指定执行的条件,如设备空闲或者充电的时候。</p>    <p><a href="/misc/goto?guid=4959675985085383233" rel="external">AlarmManager</a>并不遵循<a href="/misc/goto?guid=4959675985589162190" rel="external">Doze and App Standby</a> 的限制,它在运行任务并没有考虑<a href="/misc/goto?guid=4959675985589162190" rel="external">Doze or App Standby</a>模式。需要注意的是,应用程序如果是运行在<a href="/misc/goto?guid=4959675985589162190" rel="external">Doze or App Standby</a>模式下,是无法使用网络应用程序。</p>    <h2>Firebase JobDispatcher</h2>    <p><a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>是一个开源的库,它和系统框架的<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>非常相似。不过值得一提的是,<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>可以兼容<strong>Android</strong> 5.0以下的版本。</p>    <p><a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>支持使用<strong>Google Play services</strong>的调度去执行(运行)的工作,但这个库也允许您定义和使用其他的实现:例如,你可能会决定使用<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>或自定义。</p>    <p>如果你的应用程序需要兼容<strong>Android</strong> 5.o以下的版本,我们建议你使用<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>。</p>    <p>关于<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>的更多信息,参考其<a href="/misc/goto?guid=4959675985168705726" rel="external">文档和源代码</a>。</p>    <h2>GCM Network Manager</h2>    <p><a href="/misc/goto?guid=4959675985263538733" rel="external">GCM Network Manager</a>是<strong>Android</strong>提供一个可以兼容到5.0以下版本的<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>。它具有<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>所有的优势,但是,它依赖于<strong>Google Play services</strong>,因为是由<strong>Google Play services</strong>负责所有工作计划的安排和执行,并达到省电的目的。</p>    <p><a href="/misc/goto?guid=4959675985263538733" rel="external">GCM Network Manager</a>是<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>的较早版本。目前<a href="/misc/goto?guid=4959675985263538733" rel="external">GCM Network Manager</a>已经停止更新,我们建议您使用<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>。</p>    <h2>其他</h2>    <p>除了上面所介绍的外,还有<a href="/misc/goto?guid=4959675985350863861" rel="external">SyncAdapter</a>和<a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>,可以使您的应用程序在特定条件下,更合理的去安排工作计划和执行任务。</p>    <h3>SyncAdapter</h3>    <p><a href="/misc/goto?guid=4959675985350863861" rel="external">SyncAdapter</a>类是由系统框架所提供,它的作用是用来管理你的设备和服务器之前的同步任务。<strong>Sync adapters</strong>相对于以上的几种APIs,有着更为复杂的实现,因为它要求你至少提供<a href="/misc/goto?guid=4959675986046510921" rel="external">authenticator</a>和<a href="/misc/goto?guid=4959675986124929259" rel="external">content provider</a>的实现。因此,如果你只是简单的想在后台同步数据到云端,你应该使用<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a>、<a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>,或者<a href="/misc/goto?guid=4959675985263538733" rel="external">GCM Network Manager</a>来代替。</p>    <p>如果你的需求更贴近于 <a href="/misc/goto?guid=4959675985350863861" rel="external">SyncAdapter</a>的使用场景,那么你应该使用它。</p>    <h3>Services</h3>    <p><a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>允许您在后台运行一段长时间的操作。如果这个操作是需要与用户交互的话,我们建议你将任务放在前台的<a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>中,如播放音乐。另外,在某些使用场景下,我们建议你将<a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>绑定在用户需要去使用的那个<code>fragment</code> 或者 <code>activity</code>中。</p>    <p>在<a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>中,你应该避免使用那些无限制时间和周期性的任务,因为即便它们并没有执行,也会去耗费系统的资源。相应的,针对这些任务,您应该使用本篇文章所介绍的其他解决方案,并提供与之对应的生命周期管理。所以,针对这些特殊的任务,<a href="/misc/goto?guid=4959675985954447381" rel="external">Services</a>并不是你良好的选择方案。</p>    <h2>注意</h2>    <p>无论你采用的解决方案,请注意以下几点:</p>    <ul>     <li> <p>考虑到网络的复杂性,一些互联网门户网站,V*N,和代理可能会有网络连接检测失败的问题。一个库或一个接口可能会认为网络是可用的,但是您的服务可能无法访问。所以,你需要合理的去处理失败的情况,以及重新安排工作计划的执行。</p> </li>     <li> <p>根据您分配的条件来运行一个任务,如在网络正常连接的情况下,任务被触发后,但是如果发生一个更改,使这些条件不再满足。在这种情况下,你的操作可能会失败,或者反复的去执行。基于这个原因,你应该在任务失败的时候通知你的后台任务逻辑,并避免对资源产生一些过度的使用。</p> </li>     <li> <p>如果你使用的是<a href="/misc/goto?guid=4959675985085383233" rel="external">AlarmManager</a> ,在重新安排你的工作计划执行时,需要避免产生一些不必要的冲突。如果你使用的是<a href="/misc/goto?guid=4958860265564001864" rel="external">JobScheduler</a><br> , <a href="/misc/goto?guid=4959675985263538733" rel="external">GCM Network Manager</a>, <a href="/misc/goto?guid=4959675985168705726" rel="external">Firebase JobDispatcher</a>, 或者 sync adapters,它们则已经自动处理好这个问题。</p> </li>    </ul>    <p> </p>    <p>来自:http://hlong.xyz/2016/07/28/Android%E6%80%A7%E8%83%BD%E6%A8%A1%E5%BC%8F%E7%AF%87%E4%B9%8B%E6%99%BA%E8%83%BD%E7%9A%84%E5%B7%A5%E4%BD%9C%E8%AE%A1%E5%88%92%28%E8%AF%91%29/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io</p>    <p> </p>