3

I'm building an app which communicates with an API. I put all the API communication code and data handling in one API class so that every time I want to use the API I have a central spot where all the logic lies.

The thing is that for HTTPRequests it is strongly recommended to use AsyncTasks. As shown in the examples you create an AsyncTask by deriving the whole class.

My class consists of functions which need to be async because of the HTTP calls. Other don't.

My question: Do I just derive my whole API class from AsyncTask or shall I divide my API class even more in a normal and an async part?

3 Answers 3

2

Create an interface with 2 kind of methods, one that don't execute on other threads and other that do. Make async methods accept a callback object to be notified when they're done. Example:

public interface MyAPI {
 //--this method runs an AsyncTask and calls supplied Callback object's methods when done
 public void fetchRemoteData(String input, Callback c);

 //--this method just processes input string locally and returns it
 public String doStuff(String input);
}

public interface Callback{
  public void onDone(int doneWhatCode, String result);
}

Implementation:

public class MyWebAPI implements MyAPI{
  @Override
  public void fetchRemoteData(String input, final Callback c){
        AsyncTask<String,Void,String> task = new AsyncTask<String,Void,String>(){

            @Override
            protected String doInBackground(String... strings) {
                String i = strings[0];

                //---connect, fetch data ----
                String result = "result";

                return result;
            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                c.onDone(1,s);
            }
        };

      task.execute("new Input url");
    }

  @Override
  public String doStuff(String input){
    return input.replace("i","o");
  }
}

Let your API be exposed by these interfaces. This way you can keep it all together and also keep actual implementation separated for future changes.

3
  • but how do i tell my app that i want to call fetchRemoteData() async? your example is basically what i did but i put my http logic in a new Thread() to avoid NetworkOnMainThreadException
    – Ron
    Commented Feb 15, 2013 at 9:06
  • @Ron You implement it that way. Updated answer.
    – s.d
    Commented Feb 15, 2013 at 9:17
  • thanks! I'll give it a try and keep you up-to-date on my progress :)
    – Ron
    Commented Feb 15, 2013 at 9:29
0

Well that is kinda up to you. You could make 1 AsyncTask handling everything and doing post updates etc. but if it's a lot of different request which isn't directly related I'd separate them. A good approach might be to think about use cases and separate into different AsyncTasks based on that.

To give an example of a use case based approach:

  • Main Activity starts first AsyncTask for initialization.
  • User clicks login/or start other long running operation --> starts second AsyncTask.

Then in both cases you'd still have you old class but the AsyncTasks would call the api implemented in the old class.

0

The point here is that "you cannot use this class form a UI thread", then you create an AsyncTask. What if you had a service and wanted to call some API methods from there? You can't call AsyncTask from a service thread.
I would leave this class as it is and wrap it in an AsyncTask when I wanted to call it from UI.

EDIT: This is an example of wrapping an existing functionality into an AsyncTask:

private class GetAuthorisationUrlTask extends AsyncTask<String, Void, String>
{
    private OAuthBuilder oAuthBuilder;
    private GetAuthorisationUrlTaskCallback callback;

    public GetAuthorisationUrlTask(Context context, OAuthBuilder oAuthBuilder, GetAuthorisationUrlTaskCallback callback)
    {
        this.oAuthBuilder = oAuthBuilder;
        this.callback = callback;
    }

    @Override
    protected String doInBackground(String... params)
    {
        try
        {
            Log.i(TAG, "Getting authorization url...");
            return oAuthBuilder.getAuthorizationUrl();
        }
        catch (Exception e)
        {
            Log.e(TAG, "Unable to get OAuth authorization url: " + e, e);
            return null;
        }
    }

    @Override
    protected void onPostExecute(String result)
    {
        Log.i(TAG, "Authorisation url: " + result);
        if (result == null)
            Toast.makeText(getApplicationContext(), "Error getting authorization url.", Toast.LENGTH_SHORT).show();
        else
            callback.urlCreated(result);
    }

    static interface GetAuthorisationUrlTaskCallback
    {
        void urlCreated(String url);
    }
}

Now, you can call the AsyncTask and get a callback when the result is ready.

GetAuthorisationUrlTask getAuthorisationUrlTask = new GetAuthorisationUrlTask(this,
        new GetAuthorisationUrlTaskCallback()
        {
            @Override
            public void urlCreated(String url)
            {
                webview.loadUrl(url);
            }
        });
getAuthorisationUrlTask.execute();

I know there is so much boiler-plate code, but it separates your UI completely from the logic of your business class. It does only one single task here, but extending it to be more generic and do more without introducing new classes is easy.

1
  • same question as to @User117: how do I wrap a function into an async task? I thought you need to derive your whole class, don't you?
    – Ron
    Commented Feb 15, 2013 at 9:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.