安卓REST API客户端库

48

我们正在开发一款基于地理位置的消息应用,使用Parse.com作为后端(类似于Urban Airship / PubNub等),但现在我们希望切换到我们自己的后端以获得更好的控制。为此,我们建立了一个基于node.js的后端,通过REST API公开其功能。

为了使用这个API,我们想要构建一个Android库(类似于Parse.com的Android SDK),它抽象出所有的HTTP请求/响应或REST API调用,并提供各种操作的直接函数,如getUsers()、sendMessage()等。

在Android中实现REST API客户端的方法:

现在考虑到我们想要构建一个安卓库,同时用户正在与应用程序进行交互,可能会有同时发生的REST API调用,哪种方法最好呢?我也愿意听取其他建议/推荐。
更新:我们首先使用了IntentService + ResultReceiver来构建自己的库,效果不错。但后来我们偶然发现了Android Async Http。使用它,非常棒!

1
+1 对于 Android 异步 Http。 - Chris Rae
感谢 Async Http,感谢你提醒我相同的问题! - vishal dharankar
6个回答

43

基于2010年Google IO专业技巧,我所见过的最佳实现是RoboSpice库,它是基于REST的,并且非常巧妙地与Activity生命周期一起工作,以避免内存泄漏。

库的快速信息图表在此处:infographic,库本身在此处:here

  • Loader用于数据库,不用于REST,它们在Activity重置时被重置,这意味着你会失去你的数据。
  • Async task,不可取。
  • Intent Service + Result receiver基本上就是RoboSpice的工作方式,因此如果你正在构建自己的库,我会采用这种方法!
  • Service也不错,类似于IntentService方法,但在这种情况下,IntentService效果稍好。

Service方法可能更好,看看他们使用的robospice service 他们使用一个ExecutorService,当它没有要处理的Requests时终止Service,这比Android更多涉及Java并发。要注意的主要事项是当处理请求时服务在运行,然后如果没有剩余请求,则自行终止。

使用ExecutorService或任何类型的线程池的优点是,你可以定义同时运行多少个请求。除非你有一个非常快速的连接,否则我最多只建议你运行2-4个。


是的,我会避免使用多个IntentService方法,但是你可以使用IntentService将其传递到另一个线程,IntentService将在你将其传递给IntentService线程后继续执行。 - Chris.Jenkins
你是指在IntentService中使用AsyncTask吗?您能否详细说明如何使用Android提供的内容实际实现它? - Madhur
1
更新的答案是,Service + ThreadPool/ExecutorService 可能是最佳选择。 - Chris.Jenkins
@Chris.Jenkins RoboSpice服务的链接显示404错误。 - Stephane
@StephaneEybert 已修复香料服务的链接,感谢您的提醒。 - Chris.Jenkins
显示剩余3条评论

9
我已经使用过Retrofit,这是一个非常好的库,它提供了一种简单的结构来管理端点并解析数据/集合/对象。
文档足够完整,可以轻松编写代码。
CQFD> 就去试试吧。

8
也许这个类可以帮助您:-
/*Copyright 2014 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

package com.infotech.zeus.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import android.widget.Toast;

public class RestClient {


        JSONObject data = new JSONObject();
        String url;
        String headerName;
        String headerValue;

        public RestClient(String s){

            url = s;
        }


        public void addHeader(String name, String value){

            headerName = name;
            headerValue = value;

        }

        public void addParam(String key, String value){

            try {
                data.put(key, value);
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


        }

        public String executePost(){  // If you want to use post method to hit server

            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader(headerName, headerValue);
            HttpResponse response = null;
            String result = null;
            try {
                StringEntity entity = new StringEntity(data.toString(), HTTP.UTF_8);
                httpPost.setEntity(entity);
                response = httpClient.execute(httpPost);
                HttpEntity entity1 = response.getEntity();
                result = EntityUtils.toString(entity1);
                return result;
                //Toast.makeText(MainPage.this, result, Toast.LENGTH_LONG).show();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return result;



        }

        public String executeGet(){ //If you want to use get method to hit server

            HttpClient httpClient = new DefaultHttpClient();
            HttpGet httpget = new HttpGet(url);
            String result = null;
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            try {
                result = httpClient.execute(httpget, responseHandler);
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return result;
        }
}

一个使用该类的简单示例:

RestClient client = new RestClient("http://www.example.com/demo.php");  //Write your url here
        client.addParam("Name", "Bhavit"); //Here I am adding key-value parameters
        client.addParam("Age", "23");

        client.addHeader("content-type", "application/json"); // Here I am specifying that the key-value pairs are sent in the JSON format

        try {
            String response = client.executePost(); // In case your server sends any response back, it will be saved in this response string.

        } catch (Exception e) {
            e.printStackTrace();
        }

这是一个很棒的类,但现在你有过时错误,也许一个替代品会有帮助。 - flakerimi

4

你也可以使用RESTDroid。它与RoboSpice非常相似,但更易于使用(尽管功能也较少)。

如果您为RESTDroid创建了Parse.com模块,请务必将其添加到GitHub上!


1
你也可以尝试使用rest-spring插件和Android Annotations自动完成这些任务。

他们在spring framework for android上提供了一个包装器,并提供了一个非常好的处理rest apis的方式。

例子:

用@Background注释替换AsyncTask -> doInBackground():

@Background
protected void backgroundWork(){
    // do something in background
}

用@UiThread替换runOnUiThread和onPostExecute()

@UiThread
protected void uiWork(){
    // do something on UI Thread
}

对于REST API

创建REST客户端:

@Rest(rootUrl = "http://company.com/ajax/services",
      converters = { MappingJackson2HttpMessageConverter.class })
public interface MyRestClient {

    @Get("/events")
    EventList getEvents();
}

使用REST客户端:
@RestClient
MyRestClient myRestClient;

public void showAllEvents(){
    EventList list = myRestClient.getEvents();
    // do something with this list

}

getForObject,getForEntity 可以轻松地将数据转换为对象。使用 Jackson - ObjectMapper 的 getForObject 可以通过可选属性使生活更加轻松。 - Abhijeet

1
如果我可以再补充一件事,最近我开始编写一个不错的库来实现引擎(iOS中MKNetworkKit所使用的)和命令,以便与Android的REST API进行通信。对于任何试图访问REST API的人可能会有所帮助。https://github.com/m2d2/MDBaseAndroidLibraries

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