可以将第二种模式理解成网络版的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。视图和控制器不需要收集数据,也不需要更新模型。当数据可用时,内容提供者通知光标重新查询。数据管理的功能被封装在内容提供者内部,这种方式简化了视图和控制器中的代码。提供者客户端请求数据,并快速接收到游标;当网络数据到达时,通知游标。重要的是,是否执行通知取决于数据是否已经在本地数据库,而且只要内容提供者客户端仍在使用光标,该光标对象就不会关闭。游标和数据库关闭会导致客户端查询不到任何结果,这会造成难以确定某个组件(如列表)为空是因为错误地关闭了游标,还是某个查询确实没有结果。