我遇到了这些文章:
这引导我观看了关于REST客户端应用程序的Google I / O 2010视频。
自从现在开始,我一直在我的应用程序控制器类中将REST组件创建为静态组件。从现在开始,我认为我应该改变这种模式。某人指出Google IOSched应用程序是如何在Android上编写REST客户端的很好的示例。其他人说这种方式太过复杂。
那么,有人能否以简短简单的方式展示最佳实践呢?IOSched应用程序对于示例用例来说太复杂了。
我遇到了这些文章:
这引导我观看了关于REST客户端应用程序的Google I / O 2010视频。
自从现在开始,我一直在我的应用程序控制器类中将REST组件创建为静态组件。现在是2017年。只需使用Retrofit即可。几乎没有理由使用其他任何东西。
原始答案已经超过一年半了。虽然原始答案中提出的概念仍然有效,但正如其他答案所指出的那样,现在有一些库可以让您更轻松地完成此任务。更重要的是,其中一些库会为您处理设备配置更改。
以下是一些我评估过的Rest客户端库列表,请花时间检查它们是否适合您的用例。这个列表并不是详尽无遗的。
介绍一下我的方法,用于在Android上拥有REST客户端。虽然我不认为这是最好的方法:)但请注意,这是我根据我的需求想出来的。如果您的用例需要,您可能需要添加更多的层/增加更多的复杂性。例如,我根本没有本地存储;因为我的应用程序可以容忍丢失几个REST响应。
我的方法仅在内部使用AsyncTask
。在我的情况下,我从我的Activity
实例"调用"这些任务;但是为了完全考虑到像屏幕旋转这样的情况,您可能会选择从一个Service
或类似的位置调用它们。
我有意将我的REST客户端本身作为API。这意味着使用我的REST客户端的应用程序甚至不需要知道实际的REST URL和使用的数据格式。
客户端将具有2个层:
顶层:此层的目的是提供与REST API功能相对应的方法。例如,您可以为REST API中的每个URL(甚至为GET和POST各一个)拥有一个Java方法。
这是REST客户端API的入口点。这是应用程序通常使用的层。它可以是单例,但不一定要是。
REST调用的响应由此层解析为POJO并返回给应用程序。
这是较低级别的AsyncTask
层,它使用HTTP客户端方法实际上进行REST调用。
AsyncTask
的结果传递回应用程序。 /**
* 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();
}
Profile
。/**
* 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);
}
Activity
或Service
中使用API的示例: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
}
});
我希望评论足以解释设计;但如果需要更多信息,我很乐意提供。
GetResponseCallback
更通用。我喜欢的方法是使用 标记接口:比如 interface IGetResopnse{}
来表示所有可能成为响应的类。然后,我有 class Profile implements IGetResponse
等等。最后,使用 IGetResponse
作为上限,将 GetResponseCallback
设为通用类型:public abstract class GetResponseCallback<? extends IGetResponse>
。 - curioustechizen有另一个库,其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();
这是一项非常前沿的技术,看起来十分有前途。
我们已经将我们的轻量级异步REST客户端库开源,如果您有最小的要求并且不想自己处理多线程,那么您可能会发现它很有用 - 它非常适合基本通信,但不是完整的REST客户端库。
它被称为libRESTfulClient,可以在GitHub上找到。