安卓 REST 客户端,示例?

2022-08-31 09:11:15

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


我遇到了这些文章:

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

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

从现在开始,我认为,我应该改变模式。有人指出,Google IOSched应用程序是如何在Android上编写REST客户端的好例子。有人说,这种方式太复杂了。

那么,任何人都可以向我们展示什么是最佳实践吗?以简短而简单的方式。
IOSched 应用程序对于示例用例来说太复杂了。


答案 1

编辑2(2017年10月):

这是2017年。只需使用改造。几乎没有理由使用其他任何东西。

编辑:

在这次编辑时,原来的答案已经一年半多了。尽管原始答案中提出的概念仍然成立,但正如其他答案所指出的那样,现在有库可以使您更轻松地完成此任务。更重要的是,其中一些库会为您处理设备配置更改。

原答案保留如下,以供参考。但也请花点时间检查一些适用于Android的Rest客户端库,看看它们是否适合您的用例。以下是我评估过的一些库的列表。它绝不是要成为一份详尽无遗的清单。


原始答案:

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

我的方法只在盖子下使用s。在我的情况下,我从我的实例中“调用”这些任务;但是要充分考虑屏幕旋转等情况,您可以选择从一个或类似的地方调用它们。AsyncTaskActivityService

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

客户端将有 2 层:

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

  2. 这是较低级别的层,它使用HTTP客户端方法实际出去并进行REST调用。AsyncTask

此外,我选择使用回调机制将 s 的结果传达给应用。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();

}

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

然后,下层(AsyncTask 层)可能如下所示:

/**
 * 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(在 or 中):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
            }
        });

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


答案 2

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

我知道的唯一参考实现(如果您了解更多,请评论)可在Datadroid上找到(Google IO会话在/presentation下提到)。它是一个可以在自己的应用程序中使用的库。

第二个链接要求“最佳”REST框架,这在stackoverflow上有大量讨论。对我来说,应用程序大小很重要,其次是实现的性能。

  • 通常我使用普通的org.json implemantation,这是Android的一部分,因为API级别1,因此不会增加应用程序的大小。
  • 对我来说,非常有趣的是评论中发现的有关JSON解析器性能的信息:从Android 3.0 Honeycomb开始,GSON的流解析器包含在android.util.JsonReader中。不幸的是,评论不再可用。
  • Spring Android(我有时使用)支持Jackson和GSON。Spring Android RestTemplate Module 文档指向一个示例应用

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


推荐