Android REST client, Sample?
Asked Answered
S

7

117

Even if this thread has accepted answer, feel free to propose other ideas, you do use or like


I've met these articles:

And that lead me to this Google I/O 2010 video about REST client applications

Since now, I've been creating REST component as static component in my Application controller class.

From now, I think, I should change the pattern. Somebody pointed out that Google IOSched application is great sample of how to write REST clients on Android. Somebody else told that this ways is too overcomplicated.

So, can anybody please show us what is the best practice? In short and simple way.
The IOSched application is too complex for sample use-case.

Sodomite answered 25/11, 2011 at 10:46 Comment(4)
Hello, Generally I develop separate package for web service named "ws", I have generalize class named "WebServicUtils.java". WebServiceUtils.java class has methods to access web service. I am not sure about my technique is best or not but It is reusable every time I copy my ws package in Android Application, Let me know if you want to know more about my technique.Runck
I don't think the youtube commenter has a better alternative. We have to work within Android's APIs, even if they are often insanely over-complicated and verbose nonsense.Pilarpilaster
As a side note, Mechanoid, an open-source eclipse plugin for Android can generate JSON-REST clients using a simple DSL, a guide on how to use it can be found here robotoworks.com/mechanoid-plugin/service-client-dsl (I am the author of this plugin, sorry for the shameless plug!)Sheriff
This might be very helpful for people learning Android REST client implementation. Dobjanschi's presentation transcribed into a PDF: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…Rebato
C
102

EDIT 2 (October 2017):

It is 2017. Just use Retrofit. There is almost no reason to use anything else.

EDIT:

The original answer is more than a year and a half old at the time of this edit. Although the concepts presented in original answer still hold, as other answers point out, there are now libraries out there that make this task easier for you. More importantly, some of these libraries handle device configuration changes for you.

The original answer is retained below for reference. But please also take the time to examine some of the Rest client libraries for Android to see if they fit your use cases. The following is a list of some of the libraries I've evaluated. It is by no means intended to be an exhaustive list.


Original Answer:

Presenting my approach to having REST clients on Android. I do not claim it is the best though :) Also, note that this is what I came up with in response to my requirement. You might need to have more layers/add more complexity if your use case demands it. For example, I do not have local storage at all; because my app can tolerate loss of a few REST responses.

My approach uses just AsyncTasks under the covers. In my case, I "call" these Tasks from my Activity instance; but to fully account for cases like screen rotation, you might choose to call them from a Service or such.

I consciously chose my REST client itself to be an API. This means, that the app which uses my REST client need not even be aware of the actual REST URL's and the data format used.

The client would have 2 layers:

  1. Top layer: The purpose of this layer is to provide methods which mirror the functionality of the REST API. For example, you could have one Java method corresponding to every URL in your REST API (or even two - one for GETs and one for POSTs).
    This is the entry point into the REST client API. This is the layer the app would use normally. It could be a singleton, but not necessarily.
    The response of the REST call is parsed by this layer into a POJO and returned to the app.

  2. This is the lower level AsyncTask layer, which uses HTTP client methods to actually go out and make that REST call.

In addition, I chose to use a Callback mechanism to communicate the result of the AsyncTasks back to the app.

Enough of text. Let's see some code now. Lets take a hypothetical REST API URL - http://myhypotheticalapi.com/user/profile

The top layer might look like this:

   /**
 * 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();

}

Note that the app doesn't use the JSON or XML (or whatever other format) returned by the REST API directly. Instead, the app only sees the bean Profile.

Then, the lower layer (AsyncTask layer) might look like this:

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

Here's how an app might use the API (in an Activity or 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
            }
        });

I hope the comments are sufficient to explain the design; but I'd be glad to provide more info.

Cathode answered 2/1, 2012 at 5:53 Comment(7)
I like this answer more due to examples of quite nice code. ThanksSodomite
Probably worth nothing, this doesn't really follow a proper RESTful MVC pattern, as described by Virgil Dobjanschi. You would need to incorporate a full ContentProvider layer, which uses a SQLite database which the app directly uses. Otherwise, this is a good, lightweight REST client for Android.Chalmer
One small thing, you'll need to call execute on those Get/PostTask'sSouthworth
This is really great. How would I make the GetResponseCallback more generic, so it doesn't pass only a Profile back, or would you suggest making a seperate GetResponseCallback for each type of data from the API?Bosley
@MichaelHerbig Yes, there are ways to make GetResponseCallback more generic. The one I prefer is to use a marker interface : Like interface IGetResopnse{} to denote all classes that could be responses. Then, I have class Profile implements IGetResponse etc. Finally, make GetResponseCallback generic with IGetResponse as the upper bound : public abstract class GetResponseCallback<? extends IGetResponse>.Cathode
@MichaelHerbig I'm sorry - the last line in my previous comment should have read public abstract class GetResponseCallback<T extends IGetResponse>. The parameter should be T extends ... and not ? extends ...Cathode
RoboSplice has a pretty good list of competitors at its Github page: github.com/octo-online/robospiceBastia
C
11

"Developing Android REST client applications" by Virgil Dobjanschi led to much discussion, since no source code was presented during the session or was provided afterwards.

The only reference implementation I know (please comment if you know more) is available at Datadroid (the Google IO session is mentioned under /presentation). It is a library which you can use in your own application.

The second link asks for the "best" REST framework, which is discussed heavily on stackoverflow. For me the application size is important, followed by the performance of the implementation.

  • Normally I use the plain org.json implemantation, which is part of Android since API level 1 and therefore does not increase application size.
  • For me very interesting was the information found on JSON parsers performance in the comments: as of Android 3.0 Honeycomb, GSON's streaming parser is included as android.util.JsonReader. Unfortunately, the comments aren't available any more.
  • Spring Android (which I use sometimes) supports Jackson and GSON. The Spring Android RestTemplate Module documentation points to a sample app.

Therefore I stick to org.json or GSON for complexer scenarios. For the architecture of an org.json implementation, I am using a static class which represents the server use cases (e.g. findPerson, getPerson). I call this functionality from a service and use utility classes which are doing the mapping (project specific) and the network IO (my own REST template for plain GET or POST). I try to avoid the usage of reflection.

Colorblind answered 1/1, 2012 at 16:16 Comment(3)
The O'Reilly book, Programming Android, features a full implementation of Dobjanschi's RESTful MVC pattern (chapters 12-13).Chalmer
Thanks for the hint: I found this statement on Amazon: "Chapter 12 and 13 deal with content providers. The extensive treatment of content providers with example code and a sample application provided me several new insights in how this technology works, and how it can be used in real programming situations. The content provider framework for storing and referencing data using URIs is one of the novel features of the Android operating system. Great work in explaining the technology step by step!"Colorblind
The code is on github.com/bmeike/ProgrammingAndroid2Examples (but chapters are missing, you can find them in the first edition code github.com/bmeike/ProgrammingAndroidExamples)Colorblind
T
7

Never use AsynTask to perform network request or whatever that need to be persisted. Async Task are strongly tied to your activity and if the user change the orientation of the screen since the App is re created the AsyncTask will be stopped.

I suggest you to use Service pattern with Intent Service and ResultReceiver. Take a look to RESTDroid. It's a library that allows you to perform any kind of REST request asynchronously and notify your UI with Request Listeners implementing the Virgil Dobjanschi's service pattern.

Tusche answered 15/2, 2013 at 13:5 Comment(0)
F
3

There is another library with much cleaner API and type-safe data. https://github.com/kodart/Httpzoid

Here is a simple usage example

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
    .data(new User("John"))
    .execute();

Or more complex with callbacks

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

It is fresh new, but looks very promising.

Feltonfelts answered 14/7, 2013 at 5:45 Comment(1)
It seems to be running on AsyncTask, what is not good for long running requests and switches between activities, because AsyncTask will be killed when Activity exits.Behavior
I
1

There is plenty of libraries out there and I'm using this one: https://github.com/nerde/rest-resource. This was created by me, and, as you can see in the documentation, it's way cleaner and simpler than the other ones. It's not focused on Android, but I'm using in it and it's working pretty well.

It supports HTTP Basic Auth. It does the dirty job of serializing and deserializing JSON objects. You will like it, specially if your API is Rails like.

Interest answered 3/2, 2014 at 1:48 Comment(0)
I
1

Disclaimer: I am involved in the rest2mobile open source project

Another alternative as a REST client is to use rest2mobile.

The approach is slightly different as it uses concrete rest examples to generate the client code for the REST service. The code replaces the REST URL and JSON payloads with native java methods and POJOs. It also automatically handles server connections, asynchronous invocations and POJO to/from JSON conversions.

Note that this tool comes in different flavors (cli, plugins, android/ios/js support) and you can use the android studio plugin to generate the API directly into your app.

All the code can be found on github here.

Infecund answered 9/10, 2014 at 6:3 Comment(1)
Please replace first link with actual target instead of advertising your site.Ignition
H
0

We have open-sourced our lightweight async REST client library for Android, you might find it useful if you have minimal requirements and don't want to handle the multithreading yourself - it is very OK for basic communications but not a full-blown REST client library.

It's called libRESTfulClient and can be found on GitHub.

Havens answered 6/2, 2020 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.