Android REST客户端,示例?


115

即使该主题已接受答案,您也可以随意提出其他想法,您还是会使用或喜欢


我见过这些文章:

这使我观看了有关REST客户端应用程序的Google I / O 2010视频

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

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

那么,有人可以告诉我们什么是最佳实践吗?简而言之。
对于示例用例,IOSched应​​用程序过于复杂。


您好,通常我为名为“ ws”的Web服务开发单独的程序包,我概括了名为“ WebServicUtils.java”的类。WebServiceUtils.java类具有访问Web服务的方法。我不确定我的技术是最好还是不好,但是每次我将ws包复制到Android应用程序中时,它都是可重用的,如果您想进一步了解我的技术,请告诉我。
Ketan Parmar,

我认为YouTube评论者没有更好的选择。我们必须在Android的API中进行工作,即使它们常常过于疯狂和冗长无聊。
Timmmm 2012年

附带一提,Mechanoid是Android的开源eclipse插件,可以使用简单的DSL生成JSON-REST客户端,有关如何使用它的指南,请参见robotoworks.com/mechanoid-plugin/service-client-dsl(我是该插件的作者,对不起您的插件!)
Ian Warwick

这对于学习Android REST客户端实施的人们可能非常有帮助。Dobjanschi的演示文稿转录为PDF:drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…–
Kay Zed

Answers:


99

编辑2(2017年10月):

现在是2017年。只需使用翻新即可。几乎没有理由使用其他任何东西。

编辑:

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

原始答案保留在下面以供参考。但也请花些时间检查一些适用于Android的Rest客户端库,以了解它们是否适合您的用例。以下是我评估过的一些库的列表。它绝不是详尽的清单。


原始答案:

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

我的方法只是AsyncTask在幕后使用s。就我而言,我从Activity实例中“调用”这些任务;但要充分考虑屏幕旋转等情况,您可以选择通过Service或类似方式调用它们。

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

客户端将具有2层:

  1. 顶层:该层的目的是提供反映REST API功能的方法。例如,您可以有一个与REST API中的每个URL对应的Java方法(或者甚至有两个-一种用于GET,一种用于POST)。
    这是REST客户端API的入口点。这是应用程序正常使用的图层。它可以是单身人士,但不一定。
    该层将REST调用的响应解析为POJO,然后返回给应用程序。

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

另外,我选择使用回调机制将AsyncTasks 的结果传达给应用程序。

足够的文字。现在看一些代码。让我们假设一个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(或任何其他格式)。相反,应用程序仅看到bean 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​​的方式(在Activity或中Service):

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
            }
        });

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


我更喜欢此答案,这是因为示例代码非常不错。谢谢
Marek Sebera 2012年

1
正如Virgil Dobjanschi所述,这可能毫无价值,实际上并没有遵循正确的RESTful MVC模式。您需要合并完整的ContentProvider层,该层使用应用程序直接使用的SQLite数据库。否则,这是一个不错的,轻巧的Android REST客户端。
库珀2012年

1
一件事,您需要在这些Get / PostTask上调用execute
Mo Kargas

1
真的很棒 我将如何使GetResponseCallback更具通用性,使其不仅仅传递概要文件,还是建议您针对API中的每种数据类型分别创建GetResponseCallback?

1
@MichaelHerbig是的,有一些方法可以使GetResponseCallback通用性更高。我更喜欢使用标记接口interface IGetResopnse{} 表示所有可能是响应的类。然后,我有class Profile implements IGetResponseetc。最后,使GetResponseCallback泛型IGetResponse为上限public abstract class GetResponseCallback<? extends IGetResponse>
curioustechizen

11

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

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

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

  • 通常我使用简单的org.json实现,该实现自API级别1起就属于Android,因此不会增加应用程序的大小。
  • 对我来说,非常有趣的是在注释中找到了有关JSON解析器性能的信息:从Android 3.0 Honeycomb开始,GSON的流解析器作为android.util.JsonReader被包含在内。不幸的是,这些评论不再可用。
  • Spring Android(有时会使用)支持Jackson和GSON。所述弹簧的Android RestTemplate Module文档指向一个示例应用

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


4
O'Reilly的《 Programming Android》一书以Dobjanschi的RESTful MVC模式的完整实现为特色(第12-13章)。
库珀2012年

感谢您的提示:我在亚马逊上发现了这一说法:“第12章和第13章与内容提供者打交道。通过示例代码和示例应用程序对内容提供者的广泛处理为我提供了关于此技术如何工作以及如何实现的一些新见解。可以在实际的编程环境中使用。使用URI来存储和引用数据的内容提供程序框架是Android操作系统的新颖功能之一。在逐步解释该技术方面做得很出色!”
ChrLipp 2012年

2
代码在github.com/bmeike/ProgrammingAndroid2Examples上(但缺少章节,您可以在第一版代码github.com/bmeike/ProgrammingAndroidExamples中找到它们)
ChrLipp 2012年

有人能在ICS +上运行此代码吗?FinchVideo示例下的todo文件简洁地指出“-ICS下崩溃”。买书后发现代码示例已损坏,我有些失望...
eageranalyst 2013年

7

切勿使用AsynTask执行网络请求或任何需要保留的请求。异步任务与您的活动密切相关,如果由于重新创建了应用程序而用户更改了屏幕方向,则AsyncTask将停止。

我建议您将服务模式与Intent Service和ResultReceiver一起使用。看看RESTDroid。它是一个库,可让您异步执行任何种类的REST请求,并通过实现Virgil Dobjanschi服务模式的请求侦听器通知UI。


3

还有另一个库,其中包含更简洁的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();

它是新的,但看起来很有希望。


它似乎正在AsyncTask上运行,这对于长时间运行的请求以及在活动之间进行切换不利,因为当Activity退出时,AsyncTask将被杀死。
Malachiasz

1

有很多图书馆,我正在使用这个图书馆:https : //github.com/nerde/rest-resource。它是由我创建的,并且正如您在文档中所看到的那样,它比其他方法更干净,更简单。它不专注于Android,但我正在使用它,并且运行良好。

它支持HTTP基本身份验证。它完成了序列化和反序列化JSON对象的工作。您将喜欢它,特别是如果您的API是Rails like。


1

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

作为REST客户端的另一种选择是使用rest2mobile

该方法略有不同,因为它使用了具体的其余示例来生成REST服务的客户端代码。该代码用本机java方法和POJO替换了REST URL和JSON有效负载。它还自动处理服务器连接,异步调用和POJO与JSON的转换。

请注意,此工具具有不同的风格(cli,插件,android / ios / js支持),您可以使用android studio插件直接将API生成到您的应用中。

所有代码都可以在github上找到


3
请用实际目标替换第一个链接,而不要宣传您的网站。
Skydan

0

我们已经为Android开源了轻量级的异步REST客户端库,如果您有最低要求并且不想自己处理多线程,您可能会发现它很有用-对于基本通信来说这是很好的,但没有成熟的REST客户端图书馆。

它称为libRESTfulClient,可以在GitHub上找到

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.