48

We are building a location based messaging app which uses Parse.com as back-end (Parse.com is similar to Urban Airship/PubNub, etc) and we now want to switch to our own back-end for better control. For this, we have built a node.js based back-end with functionality exposed over REST API

To consume this API, we want to build an Android library (similar to Parse.com's Android SDK) which abstracts all the HTTP Requests/Response or REST API calls and provides direct functions for various operations like getUsers(), sendMessage(), etc

Ways to implement REST API Client in Android :

Now, considering that we want to build an android library and there could be simultaneous REST API calls while the user is interacting with the app, which approach would be the best to go ahead with ? I am open to other suggestions / recommendations as well.

UPDATE: We first built our own library using IntentService + ResultReceiver which worked fine. But we later stumbled across Android Async Http. Use it. It's awesome!

Madhur
  • 2,119
  • 1
  • 24
  • 31

6 Answers6

43

Best implimentation I have seen based on Google IO Pro Tips 2010 is the RoboSpice library, which is REST based and very cleverly works with the Activity lifecycle as to not leak memory.

Quick infographic the library is here

  • Loaders are designed for database, not REST, they are reset on activity reset meaning you loose your data.
  • Async task, just no.
  • Intent Service + Result receiver is basically how RoboSpice work, so if you are building your own lib, I would take this approach!
  • Service is also good, similar to the IntentService Method, but IntentService works a little better in this instance.

The Service method maybe better, look at the robospice service they use an ExecutorService which terminates the Service when it has run out of Requests to work through, this is more Java concurrency than Android specific. Main thing to note that the service runs whilst processing requests then terminates its self if their are none left.

The advantage of using the ExecutorService or any type of thread pool, is that you can define how many requests you can run at once. unless you have a very fast connection 2-4 is the most i would ever suggest.

Chris.Jenkins
  • 13,051
  • 4
  • 60
  • 61
  • Thanks :) That really makes the decision easier. But now i have one more question, considering we would use IntentService, Since IntenetSerive processes only one request at a time and new requests are queued how do we go about making simultaneous REST API calls ? Say, if the list of users is being retrieved (which takes ~10secs) and user tries to send a message in between of that operation ? – Madhur Nov 18 '12 at 20:43
  • Either your own version of IntentService or Accept to run one request at a time, Google has changed a lot of threading in the Android SDK to do one at a time now. Unless you need it now, the accepted convention is just process a queue of 'tasks'. Saying that, I think RoboSpice does a few requests at once, have a look at their source. – Chris.Jenkins Nov 18 '12 at 20:49
  • One ugly approach i can think of is implementing multiple IntentService which basically do the same operation of calling a REST API. That way, we can make simultaneous requests, but it would add a lot of code redundancy. Your thoughts on it ? – Madhur Nov 19 '12 at 08:50
  • Yeah I would avoid doing the multiple IntentService method, But... you can use the `IntentService` which passes it off to another thread, the `IntentService` will then move on once you pass it of the `IntentService` thread. – Chris.Jenkins Nov 19 '12 at 09:23
  • You mean AsyncTask within IntentService ? Can you please elaborate on how it can be actually implemented using stuff Android provides ? – Madhur Nov 19 '12 at 17:45
  • 1
    Updated answer, Service + ThreadPool/ExecutorService might be the best option. – Chris.Jenkins Nov 19 '12 at 21:09
  • @Chris.Jenkins The link to the RoboSpice service gives a 404. – Stephane Dec 10 '13 at 22:41
  • @StephaneEybert Fixed the link to spice service, thanks for the heads up – Chris.Jenkins Dec 16 '13 at 17:00
9

I've used Retrofit and it's really good library which provide an easy structure for managing endpoints and parse data/collections/object.

The documentation is complete enough to write easily you code.

CQFD > go for it

Hugo Gresse
  • 17,195
  • 9
  • 77
  • 119
8

MAY BE THIS CLASS CAN HELP :-

/*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;
        }
}

A SIMPLE EXAMPLE TO USE THIS CLASS :

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();
        }
Bhavit S. Sengar
  • 8,794
  • 6
  • 24
  • 34
4

You can also use RESTDroid. It's quite similar to RoboSpice but simpler to use (although also less powerful.)

If you create a Parse.com module for RESTDroid, don't hesitate to add it on GitHub!

spaaarky21
  • 6,524
  • 7
  • 52
  • 65
Pierre Criulanscy
  • 8,726
  • 3
  • 24
  • 38
1

If I may add one more thing, I recently started writing a nice library to implement Engines (as used by MKNetworkKit in iOS) and Commands to communicate with REST APIs for Android. Might be helpful for anyone trying to reach REST APIs. https://github.com/m2d2/MDBaseAndroidLibraries

dineth
  • 9,822
  • 6
  • 32
  • 39
1

You could also try Android Annotations with rest-spring plugin to do these tasks automatically.

They use a wrapper on spring framework for android and provide a really good way to handle rest apis.

Examples:

Replace AsyncTask -> doInBackground() with @Background annotation:

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

Replace runOnUiThread, onPostExecute() with @UiThread

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

For Rest API's

create rest client:

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

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

use rest client:

@RestClient
MyRestClient myRestClient;

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

}
  • [getForObject,getForEntity](http://projects.spring.io/spring-android/) can be used to marshall data to objects easily. For getForObject using [Jackson - ObjectMapper](http://tutorials.jenkov.com/java-json/jackson-objectmapper.html) make life much easier with optional attribute. – Abhijeet Jun 03 '16 at 03:42