Android consuming RestService with/without cache
<p>I am currently in the process of creating a high performance mobile application. Now i am looking at various design patterns for consuming rest services. One such pattern that stands out is the Google IO discussion <a href="http://dl.google.com/googleio/2010/android-developing-RESTful-android-apps.pdf" rel="nofollow">here</a>. How i have am looking at the code to develop this design. I will be using Spring Rest for doing the actual HTTP Rest and serialization to POJO with the Serialization Library. I came across this implementation <a href="http://www.codeproject.com/Articles/429997/Sample-Implementation-of-Virgil-Dobjanschis-Rest-p" rel="nofollow">here</a>, and will be using it as a blue print for my application. Now a major question is here. </p>

<pre><code>public interface HttpMethods {
    public Object getForObject(Object ... params);
    public Object putForObject(Object ... params);
}



   public class LocationsHttpMethods implements HttpMethods{

    private final Context mContext;

    public LocationsHttpMethods(Context context)
    {
        mContext=context;
    }
    @Override
    public Location[] getForObject(Object... params) {
        return null;
    }

    @Override
    public Object putForObject(Object... params) {
        return null;
    }

}
</code></pre>

<p>My Location is just a pojo class. Now the question that troubles me is that the second link that i have given just uses Boolean to return data. I will be returning an array of something. </p>

<pre><code>package com.confiz.rest.services;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import com.confiz.rest.providers.IProvider;
import com.confiz.rest.providers.LocationsProvider;

public class ProcessorService extends Service
{
    private Integer lastStartId;
    private final Context mContext = this;

    /**
     * The keys to be used for the required actions to start this service.
     */
    public static class Extras
    {
        /**
         * The provider which the called method is on.
         */
        public static final String PROVIDER_EXTRA = "PROVIDER_EXTRA";

        /**
         * The method to call.
         */
        public static final String METHOD_EXTRA = "METHOD_EXTRA";

        /**
         * The action to used for the result intent.
         */
        public static final String RESULT_ACTION_EXTRA = "RESULT_ACTION_EXTRA";

        /**
         * The extra used in the result intent to return the result.
         */
        public static final String RESULT_EXTRA = "RESULT_EXTRA";
    }

    private final HashMap&lt;String, AsyncServiceTask&gt; mTasks = new HashMap&lt;String, AsyncServiceTask&gt;();
    /**
     * Identifier for each supported provider.
     * Cannot use 0 as Bundle.getInt(key) returns 0 when the key does not exist.
     */
    public static class Providers
    {
        public static final int LOATIONS_PROVIDER = 1;
    }

    private IProvider GetProvider(int providerId)
    {
        switch(providerId)
        {
        case Providers.LOATIONS_PROVIDER:
            return new LocationsProvider(this);
        }
        return null;
    }

    /**
     * Builds a string identifier for this method call.
     * The identifier will contain data about:
     *   What processor was the method called on
     *   What method was called
     *   What parameters were passed
     * This should be enough data to identify a task to detect if a similar task is already running.
     */
    private String getTaskIdentifier(Bundle extras)
    {
        String[] keys = extras.keySet().toArray(new String[0]);
        java.util.Arrays.sort(keys);
        StringBuilder identifier = new StringBuilder();

        for (int keyIndex = 0; keyIndex &lt; keys.length; keyIndex++)
        {
            String key = keys[keyIndex];

            // The result action may be different for each call.
            if (key.equals(Extras.RESULT_ACTION_EXTRA))
            {
                continue;
            }

            identifier.append("{");
            identifier.append(key);
            identifier.append(":");
            identifier.append(extras.get(key).toString());
            identifier.append("}");
        }

        return identifier.toString();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        // This must be synchronised so that service is not stopped while a new task is being added.
        synchronized (mTasks)
        {
            // stopSelf will be called later and if a new task is being added we do not want to stop the service.
            lastStartId = startId;

            Bundle extras = intent.getExtras();

            String taskIdentifier = getTaskIdentifier(extras);

            Log.i("ProcessorService", "starting " + taskIdentifier);

            // If a similar task is already running then lets use that task.
            AsyncServiceTask task = mTasks.get(taskIdentifier);

            if (task == null)
            {
                task = new AsyncServiceTask(taskIdentifier, extras);

                mTasks.put(taskIdentifier, task);

                // AsyncTasks are by default only run in serial (depending on the android version)
                // see android documentation for AsyncTask.execute()
                task.execute((Void[]) null);
            }

            // Add this Result Action to the task so that the calling activity can be notified when the task is complete.
            String resultAction = extras.getString(Extras.RESULT_ACTION_EXTRA);
            if (resultAction != "")
            {
                task.addResultAction(extras.getString(Extras.RESULT_ACTION_EXTRA));
            }
        }

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }

    public class AsyncServiceTask extends AsyncTask&lt;Void, Void, Object&gt;
    {
        private final Bundle mExtras;
        private final ArrayList&lt;String&gt; mResultActions = new ArrayList&lt;String&gt;();
        private final String mTaskIdentifier;

        /**
         * Constructor for AsyncServiceTask
         * 
         * @param taskIdentifier A string which describes the method being called.
         * @param extras         The Extras from the Intent which was used to start this method call.
         */
        public AsyncServiceTask(String taskIdentifier, Bundle extras)
        {
            mTaskIdentifier = taskIdentifier;
            mExtras = extras;
        }

        public void addResultAction(String resultAction)
        {
            if (!mResultActions.contains(resultAction))
            {
                mResultActions.add(resultAction);
            }
        }

        @Override
        protected Object doInBackground(Void... params)
        {
            Log.i("ProcessorService", "working " + mTaskIdentifier);
            Object result = false;
            final int providerId = mExtras.getInt(Extras.PROVIDER_EXTRA);
            final int methodId = mExtras.getInt(Extras.METHOD_EXTRA);

            if (providerId != 0 &amp;&amp; methodId != 0)
            {
                final IProvider provider = GetProvider(providerId);

                if (provider != null)
                {
                    try
                    {
                        result = provider.RunTask(methodId, mExtras);
                    } catch (Exception e)
                    {
                        result = false;
                    }
                }

            }

            return result;
        }

        @Override
        protected void onPostExecute(Object result)
        {
            // This must be synchronised so that service is not stopped while a new task is being added.
            synchronized (mTasks)
            {
                Log.i("ProcessorService", "finishing " + mTaskIdentifier);
                // Notify the caller(s) that the method has finished executing
                for (int i = 0; i &lt; mResultActions.size(); i++)
                {
                    Intent resultIntent = new Intent(mResultActions.get(i));

                    //What to do here
                    resultIntent.put(Extras.RESULT_EXTRA, true);
                    //What to do here ends.

                    resultIntent.putExtras(mExtras);
                    resultIntent.setPackage(mContext.getPackageName());
                    mContext.sendBroadcast(resultIntent);
                }

                // The task is complete so remove it from the running tasks list
                mTasks.remove(mTaskIdentifier);

                // If there are no other executing methods then stop the service
                if (mTasks.size() &lt; 1)
                {
                    stopSelf(lastStartId);
                }
            }
        }
    }
}
</code></pre>

<p>Now if you browse to the code that contain the AsyncService, and puts the <code>resultIntent.put(Extras.RESULT_EXTRA, true);</code></p>

<p>Now how should i pass the data back to the intent. I heard Serializable is bad, and Parceable is ugly code. What else can i use. Secondly, where do i add the SQL cache retrieve code. How can i add this code to the framework. Hope i make sense. </p>
