0

I'm attempting to (In an android app) use a singleton pattern to synchronize my main thread with an intent service that makes http requests to a server. I'm having trouble understanding the proper implementation and was wondering if I might get a few pointers in the right direction.

SO, here is an example usage of the http request from the main thread:

Intent intent = new Intent(getActivity(), ClientService.class);
intent.putExtra(ClientService.REQUEST, ClientService.CLIENT_LIST_REQ);
SyncManager syncManager = SyncManager.getInstance(getActivity());
syncManager.submitHttpRequest(intent);
Log.d(TAG, syncManager.getResponse());

Here is the SyncManager singleton, which I admittedly took from a solution from an earlier topic of mine found here: Thread Synchronization with IntentService (solution by Vladimir Lichonos).

public class SyncManager {

    private static SyncManager instance;
    private Object Lock;
    private boolean hasReturned;
    private String response;
    public Context mContext;
    LinkedList<OnCompletionListener> mListeners;

    private SyncManager(Context c){
        mContext = c;
        mListeners = new LinkedList<OnCompletionListener>();
        hasReturned = false;
    }

    public static SyncManager getInstance(Context c) {
        if(instance == null){
            synchronized (SyncManager.class){
                if(instance == null){
                    instance = new SyncManager(c.getApplicationContext());
                }
            }
        }
        return instance;
    }

    //to be called by the activity/fragment
    public void submitHttpRequest(Intent intent){
        mContext.startService(intent);
    }

    public boolean checkHasReturned(){
        synchronized(Lock){
            return hasReturned;
        }
    }

    public void setReturnFlag(){
        synchronized(Lock){
            hasReturned = true;
        }
    }

    public void resetReturnFlag(){
        synchronized(Lock){
            hasReturned = false;
        }
    }

    public void setResponse(String response){
        synchronized(Lock){
            this.response = response;
        }
    }

    public String getResponse(){
        synchronized(Lock){
            return response;
        }
    }

    public void addListener(OnCompletionListener listener){
        synchronized(mListeners){
            mListeners.add(listener);
        }
    }

    public void removeListener(OnCompletionListener listener){
        synchronized(mListeners){
            mListeners.remove(listener);
        }
    }


    //to be called by the service
    public void HttpRequestComplete(){
        synchronized(mListeners){
            for (OnCompletionListener listener : mListeners){
                listener.onCompleted(this);
            }
        }
    }


    public static interface OnCompletionListener{

        public void onCompleted(SyncManager instance);

    }
}

All the stuff about listeners is from the original solution (and is currently unused in the code), and I didn't really understand how to use them, but I feel like that might be the key to correct implementation. All the stuff about Return flags and responses are mine, and they currently do not work.

Here is the significant part of the ClientService:

protected void onHandleIntent(Intent intent) {
    SyncManager syncManager = SyncManager.getInstance(getApplicationContext());
    Log.d(TAG, "entered onHandleIntent");
    int rqst = intent.getIntExtra(REQUEST, DEFAULT_REQ);
    Log.d(TAG, ""+rqst);
    String response = "";
    switch(rqst){
        case ABOUT_REQ: 
            response = getAbout();
            break;
        case VER_DATA_REQ:
            response = getVerificationData("douglas_adams_uri");
            break;
        case CLIENT_LIST_REQ:
            response = getClientList();
            break;
    }
    syncManager.setResponse(response);
    syncManager.setReturnFlag();
    return;
}

In Summary:

So, you might notice from the sample call, that what I want to be able to do is to make an HTTP call and then after that call is returned, access the data (right now i'm getting a null pointer exception in the Log.d function because that statement is being called before the 'respose' variable can be populated by the http request return). Thus, once the service is started, I want to block the thread that started it and then unblock it once the service has stopped running. The sample singleton structure given as an answer to me in an earlier thread seems promising, but I don't know how to implement the listener parts that are included. Instead, i tried to just set synchronized on a single variable, hence the parts of the SyncManager code that are not about listeners, but that does not work. Looking for more insight on how I might implement the singleton pattern to accomplish my goal of blocking the main thread while the http call is made by the intent service.

I realize some of my wording might seem overly repetitive, but i'm trying very hard to be specific b/c of past downvoting.

Community
  • 1
  • 1
bgenchel
  • 3,739
  • 4
  • 19
  • 28
  • Since Honeycomb, [`AsyncTask`](http://developer.android.com/reference/android/os/AsyncTask.html)s are executed on a single thread. So I think you probably need not write this yourself. See also http://developer.android.com/guide/components/processes-and-threads.html – flup Aug 19 '14 at 17:46
  • write what? the singleton manager? Is there another way you would have the main thread wait for the intent service? – bgenchel Aug 19 '14 at 17:49
  • why do u want the main thread to wait? – eldjon Aug 19 '14 at 17:50
  • the main thread needs to access the data that the http request is supposed to return, and so the main thread needs to wait for the request to return (aka the service to finish running) before it can access the data. – bgenchel Aug 19 '14 at 17:53
  • The onPostExecute will run on the UI thread again. – flup Aug 19 '14 at 19:07

1 Answers1

2

You don't need any singleton to achieve what you aim. Use AsyncTask see doc here. Basically you will need to overwrite the doInBackground() method, which is executed on a background thread; here you will implement the HTTPRequest delivery. The background thread will wait until it gets the response from the server (or times out) and will provide the result to the main thread by calling onPostExecute() where you can implement how to handle the results.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
eldjon
  • 2,800
  • 2
  • 20
  • 23
  • 1
    I've considered this solution, but it seemed overly complicated to me since I need to make many different types of http requests in the app. To do that, wouldn't I need to make an individual async task for each one? – bgenchel Aug 19 '14 at 18:05
  • i would say that your original solution is definitely more complicated. what so you mean more precisely "different types of http requests"? you dont need necessarily to implement different AsyncTasks. You might provide a common interface for the HTTPRequests – eldjon Aug 19 '14 at 18:09
  • yes, even though this way seems more complicated, i wanted to use it because it's supposed to provide a common interface. How would I provide a common interface with async tasks? – bgenchel Aug 19 '14 at 18:10
  • define your httprequests first – eldjon Aug 19 '14 at 18:12
  • before submitting them to the task? sorry if this sounds n00b15H, i'm not very familiar with asyncTasks. – bgenchel Aug 19 '14 at 18:39
  • i mean what does your HttpRequest look like that makes it so difficult to be applied with a AsyncTask. – eldjon Aug 19 '14 at 18:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59604/discussion-between-eldjon-and-bgenchel). – eldjon Aug 19 '14 at 18:46