Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Simple library for REST client implementation in Android
branch: master

This branch is 84 commits behind PCreations:master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
doc
libs
res
src/fr/pcreations/labs/RESTDroid
.gitignore
AndroidManifest.xml
CHANGELOG.md
README.md
ic_launcher-web.png
proguard-project.txt
project.properties

README.md

RESTDroid : REST client library for Android

Alpha release 0.7.1

RESTDroid provides a way to handle REST call to REST web-service. RESTDroid only packed fundamental logic to handle request. Extends this logic is the role of Module. Here you can found severals Module such as an ORMlite-Jackon module to handle data persistence and mapping/parsing.

RESTDroid Documentation

RESTDroid in a nutshell :

  • Make asynchronous REST request
  • You're not limited to one web service
  • Requests hold POJO's (can be your database model)
  • Network calls are not tied to your Activity, if the Activity is killed, network / database operations (ore whathever you decided to do) are still running
  • You can notify your Activities with request listeners
  • You can dynamically change the process logic via RESTDroid Module (choose to cache & persist, only debug, not to cache, or whatever you want/need by creating a new RESTDroid Module)

For contributors

TO DO FOR V1

  • Create a "Main" Service to holds request creation (in order to avoid string ID)
  • Create a CacheManager to handles cache (add a method to DaoAccess to manage that)
  • Use HttpConnection instead of apache HTTP client

User guide

Getting started

RESTDroid available Modules :

Forward and return path schema :

Forward and return parth schema

User guide

Getting started

Download RESTDroid library and add it to your Android project. Update your android manifest :


<uses-permission android:name="android.permission.INTERNET" />
<application
        ...
        <activity
            ...
        </activity>
        <service android:enabled="true" android:name="fr.pcreations.labs.RESTDroid.core.RestService"></service>
    </application>
<service android:enabled="true" android:name="fr.pcreations.labs.RESTDroid.core.RestService"></service>

Implement RESTDroid boils down to implement a RESTDroid Module or use an existing one. RESTDroid Core library implements many hooks throughout the processus on which you can attached you specific logic. See image below : Schema All you have to do it's to create a new RESTDroid Module by extending Processor and WebService classes.

Create a RESTDroid Module

Module is the class that holds your own implementation of Processor, WebService, DaoFactory and ParserFactory classes plus whatever you need. Let's consider a very simple example. We just want to create a Test Module that only display response server in LogCat and only send GET request. This Module can be usefull if you just want to test a new web-service. Of course this is a totally overkill implementation for this simple use, but it's a good way to understand how all classes works together.

First create the TestModule class and add unimplemented methods :


public class TestModule extends Module {

    @Override
    public Processor setProcessor() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ParserFactory setParserFactory() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public DaoFactory setDaoFactory() {
        // TODO Auto-generated method stub
        return null;
    }

}

As you can see a Module is just a holder class to pack all you logic. We don't need a Parser class or Dao class, remember that it's a very simple example. We need a TestProcessor, let's create it :


public class TestProcessor extends Processor {

    @Override
    protected void preRequestProcess(
            RESTRequest<ResourceRepresentation<?>> r)
            throws Exception {
        r.addHeader("Accept", "application/json");
        r.addHeader("Content-Type", "application/json");
        /* Parse.com Authentication headers */
        r.addHeader("X-Parse-Application-Id", TestWebService.APPLICATION_ID);
        r.addHeader("X-Parse-REST-API-Key", TestWebService.REST_API_KEY);
    }

    @Override
    protected void preGetRequest(
            RESTRequest<ResourceRepresentation<?>> r) {
        // TODO Auto-generated method stub
        
    }

    @Override
    protected void preDeleteRequest(
            RESTRequest<ResourceRepresentation<?>> r) {
        // TODO Auto-generated method stub
        
    }

    @Override
    protected InputStream prePostRequest(
            RESTRequest<ResourceRepresentation<?>> r) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected InputStream prePutRequest(
            RESTRequest<ResourceRepresentation<?>> r) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected int postRequestProcess(
            int statusCode, RESTRequest<ResourceRepresentation<?>> r, InputStream resultStream) {
        if(statusCode >= 200 && statusCode <= 210)
            Log.i(TestService.TAG, inputStreamToString(resultStream));
        else
            Log.i(TestService.TAG, "Error : status code = " + String.valueOf(statusCode));
        return statusCode;
    }
    
    private String inputStreamToString(InputStream is) {
        BufferedReader bufferedReader;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            StringBuilder inputStringBuilder = new StringBuilder();
            String line;
            try {
                line = bufferedReader.readLine();
                while(line != null){
                    inputStringBuilder.append(line);inputStringBuilder.append('\n');
                    try {
                        line = bufferedReader.readLine();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                return inputStringBuilder.toString();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return null;
    }

Our TestProcessor could looks like this. We are overriding only few hooks :

  • preRequestProcess hook : used here to defined some headers to add in all request. In this example I decided to use Parse.com for rapid testing, so I need to use authentication header. It's a good hook to setting them up.
  • postRequestProcess hook : used here to display in LogCat the server's response

Now let's implement the TestWebService


public class TestWebService extends WebService {

    public static final String APPLICATION_ID = "your_application_id";
    public static final String REST_API_KEY = "your_rest_api_key";
    public static final String TAG = "fr.pcreations.labs.RESTDROID.sample.TestWebService.TAG";
    
    private static final String BASE_URI = "https://api.parse.com/1/classes/";
    private static final String TEST_OBJECT = "Test/";
    
    /* Must defines this constructor for dynamic instanciation */
    public DebugWebService(Context context) {
        super(context);
    }
    
    public void getTest(RESTRequest<TestObject> r, String id) {
        get(r, BASE_URI + TEST_OBJECT + id);
    }

}

TestWebService acts as a helper. It provides a simple asynchronous API to the user interface. When implementing your own WebService class you must implement the constructor for dynamic instanciation.

getTest() takes a RESTRequest as a first argument. RESTRequest is the object that represents our request and must be parameterized with the item that will be sent/received.

In this example, I've created un Test object in Parse.com which have the following fields :

  • String objectId
  • String content
  • String title
  • String createdAt
  • String updatedAt

Let's create this ResourceRepresentation :


public class TestObject implements ResourceRepresentation<String> {

    /**
     * 
     */
    private static final long serialVersionUID = 2958835534649642979L;
    
    private String mId;
    private String mContent;
    private String mTitle;
    private Date mCreatedAt;
    private Date mUpdatedAt;
    
    public TestObject(String mId, String mContent, String mTitle,
            Date mCreatedAt, Date mUpdatedAt) {
        super();
        this.mId = mId;
        this.mContent = mContent;
        this.mTitle = mTitle;
        this.mCreatedAt = mCreatedAt;
        this.mUpdatedAt = mUpdatedAt;
    }

    public String getId() {
        return mId;
    }


    /* METHOD FOR DATA PERSISTENCE AND CACHING */

    public int getState() {
        // TODO Auto-generated method stub
        return 0;
    }

    public int getResultCode() {
        // TODO Auto-generated method stub
        return 0;
    }

    public boolean getTransactingFlag() {
        // TODO Auto-generated method stub
        return false;
    }

    public void setId(String id) {
        mId = id;
    }

    public void setState(int stateRetrieving) {
        // TODO Auto-generated method stub
        
    }

    public void setTransactingFlag(boolean transacting) {
        // TODO Auto-generated method stub
        
    }

    public void setResultCode(int resultCode) {
        // TODO Auto-generated method stub
        
    }

    /* END METHOD FOR DATA PERSISTENCE AND CACHING */

    public String getContent() {
        return mContent;
    }

    public String getTitle() {
        return mTitle;
    }

    public Date getCreatedAt() {
        return mCreatedAt;
    }

    public Date getUpdatedAt() {
        return updatedAt;
    }

    public void setmContent(String content) {
        mContent = content;
    }

    public void setmTitle(String title) {
        mTitle = title;
    }

    public void setmCreatedAt(Date createdAt) {
        mCreatedAt = createdAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        mUpdatedAt = updatedAt;
    }
    
}

Interface ResourceRepresentation is paramaterized with the type of item id field.

We're almost done, just a little obvious step : set the TestProcessor in TestModule :


public class TestModule extends Module {

    @Override
    public Processor setProcessor() {
        return new TestProcessor();
    }

    @Override
    public ParserFactory setParserFactory() {
        return null;
    }

    @Override
    public DaoFactory setDaoFactory() {
        return null;
    }

}

Use a RESTDroid Module

Using a RESTDroid Module is very simple. All you have to do is to register this module to your WebService class. It's a very small snippet :


public class TestActivity extends Activity {

    private DebugWebService ws;
    private RESTRequest<TestObject> getTestRequest;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        RESTDroid.init(getApplicationContext());
        try {
            ws = (TestWebService) RESTDroid.getInstance().getWebService(TestWebService.class);
            ws.registerModule(new TestModule());
            getTestRequest = ws.getTest(TestObject.class, "mG2hB0Xvco"); /* we want to retrieve the object with id "mG2hB0Xvco" from the 
            server */
            getTestRequest.setRequestListeners(new TestRequestListeners()); /* we now register RequestListeners class */
            ws.executeRequest(getTestRequest) /* and we execute the request */
        } catch (RESTDroidNotInitializedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        setContentView(R.layout.activity_main);
    }

    public class TestRequestListeners extends RequestListeners {
        private OnStartedRequestListener onStart = new OnStartedRequestListener() {

            public void onStartedRequest() {
                Log.i(TestWebService.TAG, "getTestRequest has started");
            }
            
        };
        
        private OnFinishedRequestListener onFinished = new OnFinishedRequestListener() {

            public void onFinishedRequest(int resultCode) {
                Log.i(TestWebService.TAG, "getTestRequest has finished with code " + resultCode);
            }
            
        };
        
        private OnFailedRequestListener onFailed = new OnFailedRequestListener() {
            
            public void onFailedRequest(int resultCode) {
                Log.i(TestWebService.TAG, "getTestRequest has failed with code " + resultCode);
            }
            
        };
        
        public TestRequestListeners() {
            super();
            addOnStartedRequestListener(onStart);
            addOnFinishedRequestListener(onFinished);
            addOnFailedRequestListener(onFailed);
        }
    }

}

We're done ! Launch your test application and you will see in LogCat the response server :). Again, this a totally overkill implementation for this use, you've seen only 10% of RESTDroid potential. Now let's take a look of a complete exemple with ORMLite for local database and Jackson for parsing/mapping and request listeners : ORMLiteJacksonModule

Something went wrong with that request. Please try again.