需要一个示例Android REST客户端项目,该项目实现了Virgil Dobjanschi的REST实现模式。

82

我希望在安卓手机上构建一个REST客户端。

这个REST服务器暴露了几个资源,例如(GET)

http://foo.bar/customer      List of all customer
http://foo.bar/customer/4711    The customer with id 4711
http://foo.bar/customer/vip     List of all VIP customer

http://foo.bar/company           List of all companys
http://foo.bar/company/4711     The company with the ID 4711
http://foo.bar/company/vip      List of all VIP companys

我(认为)我知道如何与REST服务器进行通信并获取所需的信息。 我将实现一个带有以下API的REST Client类

public List<Customer> getCustomers();
public Customer getCustomer(final String id);
public List<Customer> getVipCustomer();

public List<Company> getCompanies();
public Customer getCompany(final String id);
public List<Customer> getVipCompanies();

从Virgil Dobjanschi的演示“开发Android REST客户端应用程序”中,我了解到在Activity的Worker Thread中处理REST请求并不是一个好主意。相反,我应该使用Service API。
我喜欢有一个将绑定到(本地)服务的Singleton ServiceHelper的想法,但我担心我没有正确理解服务概念。
目前,我不明白如何将REST调用结果(在服务中异步完成)报告回调用活动。我也想知道是否需要一个处理所有REST请求(具有不同返回类型)的服务,还是是否需要一个专门的服务来处理每个REST请求。
可能我还有很多其他的理解问题,所以对我来说最好的事情是一个满足我的需求的样例应用程序。我的用例并不罕见,我希望那里有一个示例应用程序。
请告诉我吧!
任何其他指导我正确实现的建议都是有用的(Android API-Demo不符合我的用例)。
提前感谢。
Klaus 编辑:在发布此后在SO上发现类似的主题,这使我走向了我需要的方向(最小化复杂的“Dobjanschi模式”):

1
Claszen, 你有沒有對於所有請求使用單一服務和為每個請求使用專用服務的看法?如果有,能否分享一下。在我的情況下: 我有許多REST請求[約20個]可供我的應用程序使用。我看了上面提到的有價值的Google I/O會議。我的問題是哪種方法更好。是使用單一服務處理所有請求還是為每個請求使用專用服務? 我有一些要依次觸發的請求,也有一些可以同時觸發的請求。 有什麼建議嗎? - user778869
@user778869,我最终为每个(“顶级”)REST资源(如“公司”,“客户”)使用了一个IntentService和ResultReceiver。我发现这是一种“自然”的结构,并且运行良好。它可能会产生一些代码重复,但如果所有操作都在一个服务中完成,则可以避免过度使用控制结构。 - FrVaBe
这对于学习Android REST客户端实现的人可能非常有帮助。Dobjanschi的演示已转录为PDF格式:https://drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/edit?usp=sharing - Kay Zed
8个回答

50

概述

编辑:

有兴趣的人也可以看看 RESTful android,这可能会让你更好地了解它。

从实现Dobjanschi模型的尝试中我学到的是,并不是所有的东西都是铁板一块,他只是给出了一个总览,告诉你该做些什么,但这可能因应用而异,但公式是:

遵循这些思路 + 添加你自己的 = 一个愉快的Android应用程序

对于某些应用来说,模型可能因要求而异,有些应用程序可能不需要SyncAdapter的账户,而是使用C2DM。我最近做的这个例子可能会帮到某些人:


创建一个具有账户和账户管理器的应用程序

这将允许您使用SyncAdapter同步数据。这已经在创建您自己的SyncAdapter上讨论过。

创建一个ContentProvider(如果适合您的需求)

这个抽象层不仅允许您访问数据库,而且通过与REST架构具有一对一的映射方法到ServiceHelper中执行REST调用。

内容提供者 | REST 方法

查询 --------------------> GET

插入 --------------------> PUT

更新 --------------------> POST

删除 --------------------> DELETE

ServiceHelper分层

这个小伙子将基本启动一个或多个服务,使用从ContentProvider传递的参数执行一个Http(不一定是协议,但它是最常见的)REST方法。我传递了从Content Provider上的UriMatcher获取的匹配整数,这样我就知道要访问哪个REST资源,例如:

class ServiceHelper{

    public static void execute(Context context,int match,String parameters){
//find the service resource (/path/to/remote/service with the match
//start service with parameters 
    }

}

服务

执行(我大多使用IntentService)并将参数传递给helper的RESTMethod,这有什么好处?好吧,记住Service很适合在后台运行。

还要实现一个BroadCastReceiver,以便当服务完成工作时通知已注册此广播的Activity,并重新查询。我相信Virgill Conference上没有这最后一步,但我非常确定这是一个好方法。

RESTMethod类

获取参数、WS资源(http://myservice.com/service/path),添加参数,准备所有内容,执行调用并保存响应。

如果需要authtoken,则可以向AccountManager请求 如果由于身份验证而调用服务失败,则可以使authtoken无效并重新进行身份认证以获取新令牌。

最后,RESTMethod会给我提供XML或JSON,无论哪种方式,我都会基于匹配器创建处理器并传递响应。

处理器

它负责解析响应并在本地插入它。

示例应用程序?当然!

如果您对测试应用程序感兴趣,可以查看Eli-G,它可能不是最好的示例,但它遵循Service REST方法,并使用了ServiceHelper、Processor、ContentProvider、Loader和Broadcast。


谢谢你的回答。我最终为每个(“顶级”)REST资源(如“公司”,“客户”)使用了一个IntentService和ResultReceiver。Dobjanschi模型对我来说太重了。 - FrVaBe
如果你正在使用IntentService和ResultReceiver,那么你可能正在使用第一种描述的场景,即服务驱动模型。虽然他使用Binder而不是ResultReceiver进行通信,但这很好,因为我说过这并非铁规! - Necronet
我之前问过这个问题,找到了适合我的解决方案。我没有检查所有示例应用的参考文献,但由于这是最新的答案,我将接受它。尽管如此,我仍建议检查所有其他答案。 - FrVaBe
非常好的建议,检查所有答案,它们都有很多好的资源和想法!比如Jeremy提到的《Programming Android》这本书,还有Yoni提到的iosched源代码。 - Necronet
@Necronet 你好,我刚刚偶然发现了你的样例应用程序,看起来很有前途 - 但是,我在构建它时遇到了一些问题。请问你能告诉我们它需要使用哪个版本的ActionBarSherlock进行构建吗(似乎它不能与最新的ABS 4.1一起使用)?此外,从你的帖子中我并没有真正找出你是针对Dobjanschi模型的哪种模式(A、B还是C)进行开发的(我知道,你可能最终采用了一些变化,但我想你主要关注其中一种模式 - 我猜测是B模式?)谢谢! - vaiomike
这是一个相当古老的项目,我已经有一段时间没有跟进了。我使用的是 ABS 2.x,你是正确的,模式 B 使用 ContentProvider + Services,通过广播接收器通知活动重新加载数据。 - Necronet

17
《Programming Android》 一书的第13章(探究内容提供者)专门介绍了 Virgil 在 Google I/O 演讲中提出的 "第二种方案:使用 ContentProvider API"。

我们并不是唯一一个看到这种方法好处的人。在2010年5月的 Google I/O 大会上,Google 的 Virgil Dobjanschi 提出了三种模式,通过使用内容提供者将 RESTful Web 服务集成到 Android 应用程序中……

在本章中,我们将使用第二只雀鸟视频示例详细探讨第二种模式;这种策略将为您的应用程序带来许多重要的好处。由于此方法将网络操作与 Android MVC 集成的优雅性,我们将其称为“Network MVC”。

《Programming Android》的未来版本可能会涵盖另外两种方法,并记录更多关于这个 Google 演讲的细节。在您完成本章阅读后,建议您观看 Google 的演讲。

强烈推荐。

《Programming Android》作者: Zigurd Mednieks、Laird Dornin、G. Blake Meike 和 Masumi Nakamura。版权所有2011 O’Reilly Media, Inc.,978-1-449-38969-7。


11
Virgil Dobjanschi的“Developing Android REST client applications”一次关于开发Android REST客户端应用程序的讲座引起了很多讨论,因为在讲述过程中没有提供源代码,且之后也没有提供。

如果您知道更多实现,请评论。


感谢分享这个可能有用的链接(目前还没有机会深入了解) - FrVaBe
那看起来像是一个解决方案。谢谢! - Vincent Cantin

7
我们开发了一个库来解决这个问题: RoboSpice
该库使用Virgil DobjanschiNeil Goodmann描述的“服务方法”,但我们提供了一个完整的一体化解决方案,其中包括:
  • 异步执行(在后台 AndroidService 中)网络请求,将返回 POJOs(例如:REST 请求)
  • 缓存结果(以 Json、Xml、平面文本文件或二进制文件的形式)
  • 如果它们仍然存在,则通知您的活动(或任何其他上下文)网络请求的结果
  • 如果它们不再存在,则不会通知您的活动结果
  • 在其 UI 线程上通知您的活动
  • 使用简单但强大的异常处理模型
  • 支持多个 ContentServices 来聚合不同的 Web 服务结果
  • 支持请求执行的多线程
  • 是强类型的!
  • 是开源的;)
  • 经过测试

实际上,我们正在寻求社区的反馈。


4

Retrofit在这里非常有帮助,它可以根据一个非常简单的配置为您构建适配器:

Retrofit将您的REST API转换成Java接口。

public interface GitHubService {
  @GET("/users/{user}/repos")
  List<Repo> listRepos(@Path("user") String user);
}

RestAdapter类生成GitHubService接口的实现。
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .build();

GitHubService service = restAdapter.create(GitHubService.class); 生成的每个GitHubService调用都会向远程Web服务器发出HTTP请求。

List<Repo> repos = service.listRepos("octocat");

欲了解更多信息,请访问官方网站:http://square.github.io/retrofit/

注意:从Retrofit获取的适配器RestAdapter不是派生自BaseAdapter,您需要像这个SO问题一样通过某种方式对其进行包装:Why is my ListView empty after calling setListAdapter inside ListFragment?


你能否提供一个完整的示例,调用像http://api.icndb.com/jokes/random这样的REST服务? - exequielc

3

3

+1 不是我的使用场景,但无论如何这是一个很好且有用的安卓应用示例。谢谢! - FrVaBe

0

好消息,各位。 服务助手的实现在这里可用:https://github.com/MathiasSeguy-Android2EE/MythicServiceHelper 这是一个开源项目(Apache 2)。 我正在项目的初期阶段。我已经定义了需实现的模式,但尚未提取代码以创建一个干净的库。 很快就会完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接