2

I am using Loopj AsyncHttpLibrary for an android application. My purpose is to show a page containing some questions and corresponding answers. The Rest API, that I am coding against, serves questions and answers at different endpoints as:

http://example.com/docs/{id}/questions
http://example.com/docs/{id}/answers

What I'm doing right now is to make an async http request for "questions", then in the success callback of the first request, I do the second request to fetch "answers". Here is my cleaned code:

MyApiClient.getQuestions(docId, new JsonHttpResponseHandler() {
    @Override
    public void onSuccess(JSONObject questionsResponse) {

        MyApiClient.getAnswers(docId, new JsonHttpResponseHandler() {

            @Override
            public void onSuccess(JSONObject answersResponse) {

                .... Do stuff ....

            }
        });
    }
});

where MyApiClient is a static wrapper for the AsyncHttpLibrary as recommended in the library's documentation, it looks like this:

public class MyApiClient {
    private static final String BASE_URL = "http://example.com/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void getQuestions(long docId, AsyncHttpResponseHandler responseHandler) {
        get("docs/" + String.valueOf(docId) + "/questions" , null, responseHandler);
    }

    public static void getAnswers(long docId, AsyncHttpResponseHandler responseHandler){
        get("docs/" + String.valueOf(docId) + "/answers" , null, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl;
    }
}

Is there a way to start both requests without one waiting for the other to execute? I also need to be able use both http results in the same context (populating ui).

canerbalci
  • 1,239
  • 1
  • 12
  • 16
  • there is lots of ways to start both requests without one waiting for the other to execute. do you familiar with AsyncTask Class? Or Threads ? if i get correct. – Mehmet Emre Portakal May 16 '13 at 15:04
  • i am not familiar with the AsyncTask class but I have used Threads. I first tried building a Service that ran on a different thread, that handled network requests, but it turned out to be too complicated so I ended up using loopj's library. – canerbalci May 16 '13 at 15:21

2 Answers2

4

After some struggling, I found it was not that hard to hold a state of the network operations in my activity class. I ended up using two boolean vars: "fetchedQuestions" and "fetchedAnswers", which are reset to 'false ' before initializing network requests. Both requests are sent simultaneously and in their success methods, I check if the other request is finalized or not.

Here is the code (using Loopj AsyncHttpClient library)

public class MyActivity extends Activity {

    private boolean fetchedQuestions;
    private boolean fetchedAnswers;

    private JSONObject questions;
    private JSONObject answers;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        refresh();
    }

    private void refresh(){

        fetchedQuestions = false;
        fetchedAnswers = false;

        long docId = 1;

        MyApiClient.getQuestions(docId, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(JSONObject questionsResponse) {
                questions = questionsResponse;  
                fetchedQuestions = true;
                if (fetchedAnswers)
                    populatePage();

            }
        });

        MyApiClient.getAnswers(docId, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(JSONObject answersResponse) {
                answers = answersResponse;  
                fetchedAnswers = true;
                if (fetchedQuestions)
                    populatePage();

            }
        });
    }

    private void populatePage(){
        // do stuff with "questions" and "answers"
    }     

}

where MyApiClient is defined as

public class MyApiClient {
    private static final String BASE_URL = "http://example.com/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void getQuestions(long docId, AsyncHttpResponseHandler responseHandler) {
        get("docs/" + String.valueOf(docId) + "/questions" , null, responseHandler);
    }

    public static void getAnswers(long docId, AsyncHttpResponseHandler responseHandler){
        get("docs/" + String.valueOf(docId) + "/answers" , null, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl;
    }
}
canerbalci
  • 1,239
  • 1
  • 12
  • 16
  • Does it work? the flag may not be changed before you call that if statement. maybe change it to while(flag) works? – hakunami Mar 28 '14 at 04:05
  • Yes it works. Both "if" blocks reside in async onSuccess functions, they are called once a query is finished. They check if the other query is finished before them or not. – canerbalci Mar 28 '14 at 13:23
1

Hope this helps:

public class SampleActivity extends Activity{

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new GetQuestionsThread().execute();
        new GetAnswersThread().execute();
    }

    public class GetQuestionsThread extends AsyncTask<Void, Void, String> {
        public GetQuestionsThread() {

        }

        @Override
        protected String doInBackground(Void... params) {

            //make post

            return request;
        }

        @Override
        protected void onPostExecute(LString result) {
            // do something with result
        }
    }

    public class GetAnswersThread extends AsyncTask<Void, Void, String> {
        public GetAnswersThread() {

        }

        @Override
        protected String doInBackground(Void... params) {
            //make post
            return request;
        }

        @Override
        protected void onPostExecute(LString result) {
            // do something with result
        }
    }

}
Mehmet Emre Portakal
  • 1,774
  • 21
  • 37
  • Thank you very much for your response. I tried to get this method working but the responses are not in the same context so there is no way of telling if the "questions" are fetched when I get "answers" or vice versa. Since I mentioned the Loopj's library in the title I updated the thread with my solution using that library. – canerbalci May 17 '13 at 07:40