Android REST client, Sample?

即使这个帖子已经接受了答案,请随时提出其他想法,你确实使用或喜欢


我见过这样的文章:

这让我想到了这个关于 REST 客户端应用程序的 Google I/O 2010视频

从现在开始,我一直在 Application 控制器类中创建作为静态组件的 REST 组件。

从现在开始,我想,我应该改变模式。Somebody指出,谷歌 IOSching应用程序是如何在 Android 上编写 REST 客户端的一个很好的例子。其他人告诉我,这种方式太过复杂。

那么,谁能告诉我们什么是最佳实践? 简单明了。
IOSched 应用程序对于示例用例来说太复杂了。

148999 次浏览

Virgil Dobanschi 的“开发 Android REST 客户端应用程序”引发了很多讨论,因为在会议期间没有提供源代码,也没有在会议之后提供源代码。

我所知道的唯一的参考实现(如果您知道更多,请注释)可以在 数据机器人上获得(Google IO 会话在/幻灯片下提到)。它是一个库,您可以在自己的应用程序中使用它。

第二个链接要求使用“最好的”REST 框架,这个框架在堆栈溢出方面有很多讨论。对我来说,应用程序的大小很重要,其次是实现的性能。

  • 通常我使用普通的 org.json 实现,这是自 API 级别1以来 Android 的一部分,因此不会增加应用程序的大小。
  • 对于我来说非常有趣的是在 JSON 解析器性能的评论中发现的信息: 从 Android 3.0 Honeycomb 开始,GSON 的流解析器包含在 Android.util 中。JsonReader.不幸的是,评论已经不再可用了。
  • Spring Android (which I use sometimes) supports Jackson and GSON. The Spring Android RestTemplate Module 文档 points to a sample app.

因此,对于复杂的场景,我坚持使用 org.json 或 GSON。对于 org.json 实现的体系结构,我使用了一个表示服务器用例的静态类(例如 findPerson、 getPerson)。我从一个服务中调用这个功能,并使用实用程序类进行映射(特定于项目)和网络 IO (我自己的用于普通 GET 或 POST 的 REST 模板)。我尽量避免使用反射。

编辑2(2017年10月) :

现在已经是2017年了,只要使用“改造”就行了。几乎没有理由使用其他任何东西。

编辑:

原来的答案是一年半以上,在这个编辑的时候。尽管原始答案中提出的概念仍然有效,正如其他答案指出的那样,现在已经有一些库可以使这项任务变得更加容易。更重要的是,其中一些库可以为您处理设备配置更改。

原答案保留如下,以供参考。但是也请花些时间检查一下其他 Android 客户端库,看看它们是否适合你的用例。下面是我评估过的一些库的列表。这绝不是一个详尽无遗的清单。


原答案:

介绍在 Android 上使用 REST 客户端的方法。但我并不认为这是最好的:)另外,请注意,这是我根据自己的需求想出来的。如果您的用例需要,您可能需要更多的层/添加更多的复杂性。例如,我根本没有本地存储,因为我的应用程序可以容忍一些 REST 响应的丢失。

我的方法只是在掩护下使用 AsyncTask。在我的例子中,我从我的 Activity实例“调用”这些任务; 但是为了充分考虑屏幕旋转这样的情况,您可以选择从 Service或类似的实例调用它们。

我有意识地选择 REST 客户端本身作为一个 API。这意味着,使用我的 REST 客户端的应用程序甚至不需要知道实际的 REST URL 和所使用的数据格式。

客户端将有两个层次:

  1. 顶层: 这个层的目的是提供方法,这些方法反映了 REST API 的功能。例如,您可以有一个与 REST API 中的每个 URL 对应的 Java 方法(或者甚至有两个——一个用于 GET,一个用于 POST)。
    这是 REST 客户端 API 的入口点。这是应用程序通常使用的图层。可能是一个独生子,但不一定。
    REST 调用的响应由该层解析为 POJO 并返回给应用程序。

  2. This is the lower level AsyncTask layer, which uses HTTP client methods to actually go out and make that REST call.

另外,我选择使用 Callback 机制将 AsyncTask的结果传递回应用程序。

足够的文本。让我们现在看一些代码。让我们采取一个假设的 REST API URL-http://myhypotheticalapi.com/user/profile

顶层可能看起来像这样:

   /**
* Entry point into the API.
*/
public class HypotheticalApi{
public static HypotheticalApi getInstance(){
//Choose an appropriate creation strategy.
}
    

/**
* Request a User Profile from the REST server.
* @param userName The user name for which the profile is to be requested.
* @param callback Callback to execute when the profile is available.
*/
public void getUserProfile(String userName, final GetResponseCallback callback){
String restUrl = Utils.constructRestUrlForProfile(userName);
new GetTask(restUrl, new RestTaskCallback (){
@Override
public void onTaskComplete(String response){
Profile profile = Utils.parseResponseAsProfile(response);
callback.onDataReceived(profile);
}
}).execute();
}
    

/**
* Submit a user profile to the server.
* @param profile The profile to submit
* @param callback The callback to execute when submission status is available.
*/
public void postUserProfile(Profile profile, final PostCallback callback){
String restUrl = Utils.constructRestUrlForProfile(profile);
String requestBody = Utils.serializeProfileAsString(profile);
new PostTask(restUrl, requestBody, new RestTaskCallback(){
public void onTaskComplete(String response){
callback.onPostSuccess();
}
}).execute();
}
}




/**
* Class definition for a callback to be invoked when the response data for the
* GET call is available.
*/
public abstract class GetResponseCallback{
    

/**
* Called when the response data for the REST call is ready. <br/>
* This method is guaranteed to execute on the UI thread.
*
* @param profile The {@code Profile} that was received from the server.
*/
abstract void onDataReceived(Profile profile);
    

/*
* Additional methods like onPreGet() or onFailure() can be added with default implementations.
* This is why this has been made and abstract class rather than Interface.
*/
}


/**
*
* Class definition for a callback to be invoked when the response for the data
* submission is available.
*
*/
public abstract class PostCallback{
/**
* Called when a POST success response is received. <br/>
* This method is guaranteed to execute on the UI thread.
*/
public abstract void onPostSuccess();


}

注意,应用程序不直接使用 RESTAPI 返回的 JSON 或 XML (或任何其他格式)。相反,应用程序只能看到 bean Profile

Then, the lower layer (AsyncTask layer) might look like this:

/**
* An AsyncTask implementation for performing GETs on the Hypothetical REST APIs.
*/
public class GetTask extends AsyncTask<String, String, String>{
    

private String mRestUrl;
private RestTaskCallback mCallback;
    

/**
* Creates a new instance of GetTask with the specified URL and callback.
*
* @param restUrl The URL for the REST API.
* @param callback The callback to be invoked when the HTTP request
*            completes.
*
*/
public GetTask(String restUrl, RestTaskCallback callback){
this.mRestUrl = restUrl;
this.mCallback = callback;
}
    

@Override
protected String doInBackground(String... params) {
String response = null;
//Use HTTP Client APIs to make the call.
//Return the HTTP Response body here.
return response;
}
    

@Override
protected void onPostExecute(String result) {
mCallback.onTaskComplete(result);
super.onPostExecute(result);
}
}


/**
* An AsyncTask implementation for performing POSTs on the Hypothetical REST APIs.
*/
public class PostTask extends AsyncTask<String, String, String>{
private String mRestUrl;
private RestTaskCallback mCallback;
private String mRequestBody;
        

/**
* Creates a new instance of PostTask with the specified URL, callback, and
* request body.
*
* @param restUrl The URL for the REST API.
* @param callback The callback to be invoked when the HTTP request
*            completes.
* @param requestBody The body of the POST request.
*
*/
public PostTask(String restUrl, String requestBody, RestTaskCallback callback){
this.mRestUrl = restUrl;
this.mRequestBody = requestBody;
this.mCallback = callback;
}
        

@Override
protected String doInBackground(String... arg0) {
//Use HTTP client API's to do the POST
//Return response.
}
        

@Override
protected void onPostExecute(String result) {
mCallback.onTaskComplete(result);
super.onPostExecute(result);
}
}
    

/**
* Class definition for a callback to be invoked when the HTTP request
* representing the REST API Call completes.
*/
public abstract class RestTaskCallback{
/**
* Called when the HTTP request completes.
*
* @param result The result of the HTTP request.
*/
public abstract void onTaskComplete(String result);
}

下面是应用程序可能如何使用 API (在 ActivityService中) :

HypotheticalApi myApi = HypotheticalApi.getInstance();
myApi.getUserProfile("techie.curious", new GetResponseCallback() {


@Override
void onDataReceived(Profile profile) {
//Use the profile to display it on screen, etc.
}
            

});
        

Profile newProfile = new Profile();
myApi.postUserProfile(newProfile, new PostCallback() {
            

@Override
public void onPostSuccess() {
//Display Success
}
});

我希望这些评论足以解释这个设计,但是我很乐意提供更多的信息。

永远不要使用 AsynTask 来执行网络请求或任何需要持久化的操作。AsyncTask 与您的活动紧密相连,如果用户在应用程序重新创建后改变了屏幕的方向,AsyncTask 将被停止。

我建议您对意图服务和 ResultReceiver 使用 Service 模式。看看 RESTDroid。它是一个库,允许您异步执行任何类型的 REST 请求,并使用实现 Virgil Dobjecanschi 服务模式的请求监听器通知 UI。

还有另一个库,它具有更清晰的 API 和类型安全的数据。 Https://github.com/kodart/httpzoid

下面是一个简单的用法示例

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
.data(new User("John"))
.execute();

或者更复杂的回调

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
.data(new User("John"))
.handler(new ResponseHandler<Void>() {
@Override
public void success(Void ignore, HttpResponse response) {
}


@Override
public void error(String message, HttpResponse response) {
}


@Override
public void failure(NetworkError error) {
}


@Override
public void complete() {
}
}).execute();

它是新的,但看起来很有前途。

这里有很多库,我正在使用这个: https://github.com/nerde/rest-resource。这是由我创建的,正如您在文档中所看到的,它比其他的要干净和简单得多。它不是专注于 Android,但我正在使用它,它工作得非常好。

It supports HTTP Basic Auth. It does the dirty job of serializing and deserializing JSON objects. You will like it, specially if your API is Rails like.

免责声明: 我参与了 rest2mobile 开源项目

作为 REST 客户机的另一种选择是使用 Rest2mobile

The approach is slightly different as it uses concrete 其他例子 to generate the client code for the REST service. The code replaces the REST URL and JSON payloads with native java methods and POJOs. It also automatically handles server connections, asynchronous invocations and POJO to/from JSON conversions.

请注意,这个工具有不同的风格(cli、插件、 android/ios/js 支持) ,您可以使用 安卓工作室插件直接在应用程序中生成 API。

所有代码都可以在 我是 Github上找到。

我们已经为 Android 开源了我们的轻量级异步 REST 客户端库,如果你有最小的需求并且不想自己处理多线程的话,你可能会发现它很有用——对于基本的通信来说它是非常好的,但是不是一个完整的 REST 客户端库。

它叫做 libRESTfulClient 和 可以在 GitHub 上找到