基于Android的音乐播放器系统的设计与实现外文翻译资料

 2022-09-15 15:16:30

英语原文共 564 页,剩余内容已隐藏,支付完成后下载完整资料


第十三章 内容提供者作为RESTful Web服务的Facade

在第6章中,我们看到了用户界面要与远程服务交互时面对着一些较大的挑战,比如对长时间运行的任务不捆绑UI线程。我们在第3章也同样指出,Android的内容提供者API共享方式和REST风格的Web服务间的对应关系。内容提供者的数据操作可以直接映射到REST风格的数据操作,现在我们将向你展示如何使用内容提供者的URI来请求网络数据。我们建议利用这种对称性的优势,在实现内容提供者时,把它作为位于应用和需要从应用获取数据的网络请求之间的异步缓冲区。使用这种方式编写的应用会大大简化你的程序,而且可以解决在Android和其他Java编程中遇到的一些常见的UI和网络编程错误。

一般而言,Java UI 程序员对企业应用和移动应用,编写的移动和桌面应用都过于脆弱,而且有时直接在UI线程上执行了网络请求,通常情况下也没有缓存这些请求所获取到的数据。在大多数应用中,用户每次请求时,在UI上显示的所有数据都需要通过网络来获取。信不信由你,在20世纪80年代和90年代,当远程的文件系统不可用时,Unix工作站经常死机。如果应用程序采用了本地动态缓存方案,当无法访问远程文件系统时,这些工作站还可以继续运行,然后在可以访问时再同步数据。虽然这种情况不常发生,但开发人员仍需注意确保其应用能够正确的访问和存储网络数据。

在J2ME中仍然存在这个问题,开发人员会把网络状态缓存到名为RMS的记录管理系统中。这个RMS库不支持查询,也不支持MVC通知机制。J2ME开发人员需要扩展自己的纯Java线程以完成网络请求,但在许多情况下并没有用反而导致应用很脆弱。如果Web浏览器需要在UI线程上加载网络数据,你会经常发现当因网络而导致UI线程被锁定时,Web浏览器就会完全僵死了,必须由操作系统杀死这个进程才能退出。浏览器显示所有页面和图片在每次浏览时都需要下载,这使得用户有一个非常缓慢的感觉——假如其中的一个请求没有使整个应用终止。造成这种现象的一个原因是,操作系统把加载和缓存网络数据的工作全部留给应用,只提供很少的库来帮助开发人员正确地完成这些任务。

为了解决这些问题,你可以使用一个完全异步的接口来处理网络交互和数据存储。有了这种方法,开发人员不需要思考什么时候去请求网络数据是可以的——是否在UI线程上使用该API始终都是安全的。在一个移动的环境中,这种考虑更加重要,因为间歇性的网络连接增加了不正确的代码被终止的可能性。

我们建议使用内容提供者API作为网络的异步模型和网络状态的缓存,这样你的应用程序视图和控制器不需要自己的打开连接或访问数据库的机制。这可以很容易的把provider的API映射到已有的基于REST的Web服务的API——提供者只是简单的位于应用间,将请求转发到网络,并根据需要缓存结果。再这一章节中,我们将说明这种方式会如何简化你的应用,我们会解释这种技术更广泛的优势,包括它如何把Web和AJAX编程的一些好的特性结合起来应用到Android应用中。如果你想了解关于AJAX编程的更多信息,可以去这个网站查阅http://en.wikipedia.org/wiki/Ajax_(programming)。

开发RESTful类型的Android应用

我们并不是唯一看到这种方法的好处的人。在2010年5月的Google I/O会议上,Google的Virgil Dobjanschi在讲话中介绍了以下这3种使用内容提供者把RESTful Web服务整合到Android应用中的模式:

Activity→Service→ContentProvider

这种模式涉及到活动通过服务来访问应用数据,服务又反过来将数据的访问委托给内容提供者。在这种情况下,活动在服务上调用一种异步方法,它执行异步RESTful调用。

Activity→ContentProvider→Service

活动联系内容提供者,内容提供者又反过来委托服务异步加载该数据。这种方式使得活动可以利用内容提供者API和数据交互的便利性。内容提供者调用异步服务来获取一个RESTful请求。这种方式利用了内容提供者API和HTTP的RESTful使用方式的相互对应。.

Activity→ContentProvider→SyncAdapter

Android的同步适配器为设备和云存储之间用户数据的同步提供了一个框架。Google Contacts采用的就是同步适配器。在这种情况下,一个活动使用内容提供者API来获得同步适配器同步的数据。

在这一章节中,我们将在我们第二个Finch视频示例中详细的探索第二种模式;这种策略会给你的应用带来很多便利。由于这种方式很完美地把网络操作结合到了Android MVC中,我们称它为“Network MVC”。

当你读完这一章节的内容后,我们建议你可以看看Google的视频。

Network MVC

我们更喜欢将第二种模式作为网络版的MVC,内容提供者自己本身从网络中获取数据,然后再把这些数据传递给正规的Android MVC。我们会看见内容提供者作为一种网络状态模型——提供者可以在数据请求中包含本地状态,也可以从网络中获取数据。通过这种方式,控制器和视图代码不应该直接创建网络请求来访问和管理应用程序数据。相反,你的应用程序视图和控制器应该使用ContentResolver API通过内容提供者进行数据查询,内容提供者会异步加载网络资源并把结果保存到本地缓存中。此外,提供者应该通过尽量避免网络调用,来始终做到优先使用本地数据库的数据来快速响应请求。通过这种方式处理请求可以确保UI线程不会被无缘无故的阻塞,UI也可以尽快的显示某些数据,从而提高了用户使用UI时的整体满意度。下面是关于提供者序列用于查询数据的详细信息:

1.提供者匹配传入的URI,查询本地数据库,获取已有的能够匹配该查询的内容项。

2.我们的提供者总是试图获取查询的最新状态,扩展异步REST请求,从网络中加载内容。你可以把该行为根据请求进行配置。

3.提供者给客户端返回在最初的本地查询中的光标。

4.异步加载线程应该决定在提供者缓存中的数据是否需要被刷新;如果需要刷新,提供者就从网络中加载和解析数据。

5.当网络上有新的内容时,提供者直接向数据库中插入每一个新的数据项,然后通知该URI的客户端。因为在内容提供者中已经执行了插入操作,所以不需要调用ContentResolver.insert方法。拥有包含老版本数据的光标的客户端可以调用Cursor.requery方法来刷新数据。

有了这个序列,视图和控制器最终会更新网络数据,但只有内容提供者会创建网络请求。我们把对当前不在提供者的数据集中的资源请求作为加载资源请求——网络请求会向缓存中加载数据是活动提供者查询的负面效果。

图13-1说明了在上述操作序列执行期间,内容提供者内部所执行的操作序列。

图13-1:网络提供者替客户端缓存数据

对于每个查询来说,这个序列使用提供者创建了一个唯一的Cursor对象,然后返回到视图。当数据发生变化时,只需要提供者通知UI。视图和控制器不需要收集数据,也不需要更新模型。当数据可用时,内容提供者通知光标查询。数据管理的功能被封装在内容提供者内部,这简化了视图和控制器中的代码。提供者客户端请求数据并快速接收到光标;当网络数据到达时,光标被通知。重要的是,是否执行通知取决于数据和Cursor对象是否已经在本地数据库,而且只要内容提供者客户端仍在使用光标,该光标对象就不会关闭。关闭光标和数据库会导致客户端查询不到任何结果,这会造成很难确定某个组件(如列表)为空是因为它的光标被错误地关闭了,还是因为某个查询确实没有任何结果。

Network MVC方式的优点小结

总结Network MVC模式的优点是很有意义的:

·提升了整体的感知性能,而通过缓存提升了实际性能是这种模式的主要优势之一。移动编程通常在实现上类似于Web编程,没有缓存系统。

·在内存中保存数据不是一个好的想法,因为你不知道Android什么时候会从内存中删除你的活动。这种模式强调的是尽可能快地把数据保存在内容提供者中。

·大部分可能发生的UI线程安全问题也不会发生。Android视图组件已经实现了动态更新来显示当前的光标内容。如果模型中的数据变少,ListView组件会确保减少其在光标上遍历的次数。对于熟悉J2SE Swing的读者来说,他们知道其他组件系统会把这种类型的任务留给开发人员,这会导致列表组件在数据元素被删除的情况下执行迭代时,访问可能会超出模型的边界。

·这种方法利用光标管理系统和用户接口中天然存在的动态更新能力来实现对内容变化事件的响应。用户接口开发人员不需要编写他们自己的投票和更新系统;他们只需要依赖内容观察者和内容提供者接口。

·对于任何正确的网络资源请求,UI线程不可能会挂在网络上。

·网络事件的发生不需要用户界面的存在。即使当一个网络事件到达时也不需要一个特定的活动,内容提供者仍然要处理它。当用户加载活动时,可以查询显示在后台的到达的事件。缺乏一个活跃的UI活动也不会使得事件简单地消失不可见。

·应用程序的元素是封装的,并且有特殊的目的,因为正如我们前面提到的,内容提供者处理所有的网络和SQLite的交互。视图和控制器只是将提供者作为一个通用系统是来进行数据管理。

·编写应用程序更加简单,因为使用的API很少会出错——执行内容提供者调用,系统处理REST(双关语意)。

·最后,在一本关于移动编程的书中,往往把重点放在设备的问题上,但是如果客户端依赖于其缓存,而且只有当必须的时候才指向网络,这会极大的减少为设备提供数据服务的系统的网络负载。这种模式为服务器和客户端都提供了一个显著的优势。

这种方式在实际中的一种应用

需要明确的是,只要可能,我们建议应用程序应该通过内容提供者来访问和存储网络数据。虽然这在一开始看起来像是一个很繁重的工作,但是考虑到Web浏览器也是使用异步机制来加载URI所引用的内容的。对于熟悉基础的Web编程的读者来说,默认的Android API可能比AJAX API更加灵活和广泛,但是AJAX有很完善的架构。现代浏览器通过使用异步I/O机制来加载URI数据(见http://en.wikipedia.org/wiki/Asynchronous_io),这在很多情况下可以避免浏览器用户界面终止。虽然当某个URI加载失败时浏览器看起来没执行什么,但UI线程自己本身从来不会因为网络连接没有响应而造成阻塞。如果UI线程快要终止时,整个浏览器就会停止工作。浏览器甚至都没法告诉你它终止了——尤其是因为很多浏览器是完全单线程的。相反,浏览器能够停止对任何给定页面的加载请求,然后加载另一个可能响应更好的页面。进一步说,所有的现代浏览器都利用了持久性的Web缓存,我们仅仅建议Android应用系统也应该包含类似的结构。

除了我们所描述的模式外,Google还提供了专门的关于提高应用程序的响应能力的文档,以及减少“应用程序不响应”通知的可能性的文档,这些文档在http://developer.android.com/guide/practices/design/responsiveness.html。

代码实例:动态列出并缓存YouTube视频内容

为了证明前面的架构,我们一起来看一下Finch视频列表应用,它支持用户使用RESTful API在手机上从http://gdata.youtube.com搜索视频。我们的示例代码的设计主要针对移动环境的间歇性连接这一特性。应用程序保存了用户数据,因此即使在网络连接不可用时,应用程序还是可用的——虽然这可能意味着此时我们应用程序只能显示老的、本地缓存的结果。

当用户运行查询时,应用程序会尝试为该查询检索最新的YouTube结果。如果应用程序成功地加载了新的结果,它会把一周之前的结果删除掉。如果应用程序在运行更新查询前,只是一味地丢掉老的结果,这可能会导致没有任何结果可以显示,这会造成应用程序在网络连接重新前不可用。图13-2所示的屏幕显示了一次关键字为“dogs”的查询。在搜索框中按下Enter键或者单击刷新按钮就会生成新的查询。

图13-2:Finch视频示例应用

我们的应用程序包含一个缓存查询内容提供者,它负责通过查询YouTube API来获取YouTube的视频元数据。查询结果被缓存在名为video的SQLite表中,作为内容提供者的查询方法的一部分。提供者利用了Finch框架来异步调用REST请求。UI包含如图13-2所示的活动,1个搜索查询框的列表和刷新按钮。列表动态刷新内容提供者的数据通知。当用户输入一个搜索查询并按下Enter键时,活动会在FinchVideoContentProvider上以合适的URI查询调用查询请求。下面我们将详细探讨这个例子。

Finch YouTube视频示例的源代码结构

本节简要探讨了Finch YouTube视频应用程序中相关的Java源代码,它和简单的视频列表应用程序不同。首先,文件被保存在两个不同的目录中:保存第12章中的Finch视频应用程序的目录和第12章依赖的Finch框架库所在的目录。YouTube应用程序的源文件包括:

在$(FinchVideo)/src/目录下的第12章给出的文件

$(FinchVideo)/src/com/oreilly/demo/pa/finchvideo/FinchVideo.java

FinchVideo类包含Video类,它和简单的视频应用FinchVideo.SimpleVideos的功能相同。FinchVideo.Videos类定义了一些常量,以及简单视频应用版本中所定义的内容提供

剩余内容已隐藏,支付完成后下载完整资料


资料编号:[148744],资料为PDF文档或Word文档,PDF文档可免费转换为Word

您需要先支付 30元 才能查看全部内容!立即支付

课题毕业论文、开题报告、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。