Monday, February 8, 2016

Network Request and JSON with AsyncHttpClient



While Android has its own mechanisms to make network requests, the process is a bit cumbersome and verbose. More than a few 3rd party libraries have been created to help this such as OkHttp and Volley. However, the fine folks at CodePath recommend Asynchronous Http Client by James Smith, used by Pinterest, Instagram, and lots others.

To get started, simply import the library into your project by adding a few lines to your build.grade file:


repositories {
  maven {
    mavenCentral()
  }
}
dependencies {
  compile 'com.loopj.android:android-async-http:1.4.9'
}


Next, create a new class for your http client. This approach, as opposed to setting things up in your activity, will keep your code much cleaner and more compact, especially when (not if) you decide to add more features to your app.

public class DataClient {

    private static final String API_URL = "http://www.mydomain.com/api/";
    private static final String API_KEY = "841kas90GvepScwKJrb j190da";

    private final int TIMEOUT = 20 * 1000;

    // Constructor - can set timeout, basic auth, and other features here
    public DataClient() {
        client = new AsyncHttpClient();
        client.setTimeout(TIMEOUT);
    }

    // The actual request, this one with params. This library also supports 
    // headers, even in API 23
    public void getData(JsonHttpResponseHandler handler) {
        String url = API_URL;
        RequestParams params = new RequestParams("key", API_KEY);
        client.get(url, params, handler);
    }

}


Back in your activity, you can now create a new instance of your DataClient and call your  getData() method.  Since the JSON object is already created for you in the callback, it is ready for parsing.


DataClient client = new DataClient();
client.getLeagueEventData(new JsonHttpResponseHandler() {

    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONObject body) {
        // Response is already in JSON format and ready for parsing
        parseJsonResponse(body);
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
        // Handle errors here
        super.onFailure(statusCode, headers, throwable, errorResponse);
        Log.d(TAG, "Error: " + errorResponse);
    }
});


AsyncHttpClient also offers the ability to return JSON arrays, binary and file response handlers, and lots of other cool features that make life easy.

Wednesday, February 3, 2016

Callbacks with Interfaces


Often times you will run into a scenario where you will need to signal that an event has happened, or will need to accomplish the same specific task in multiple activities. Since writing duplicate code is poor practice, you can use the common "listener" or "observer" pattern as a means to solve both of these issues. The steps below will show you how to implement this pattern.


Step 1: Define interface

public interface EventListener {
   void onEventHappened();
}


Step 2: In a worker class, define an instance of EventListener and create a setter. Then create a public method where the EventListener object will call the callback method in the calling activity.

public class WorkerClass {

   private EventListener listener;

    // Create setter for the listener
   public void setListener(EventListener listener) {
      this.listener = listener;
   }


 
   public void doWork() {

      // ... do calculations, make network call, etc. here
      
      // This will trigger onEventHappened() in CallingActivity
      listener.onEventHappened("Work was done!");
   }

}


Step 3: Create a WorkerClass variable and set the listener. You can now call doWork(), which will contains a method call to trigger onEventHappened() (your callback method).

public class CallingActivity implements EventListener {

    WorkerClass worker = new WorkerClass();
    
    // Pass in 'this' to setListener()
    worker.setListener(this);

    // Call the worker method in WorkerClass
    worker.doWork();


    @Override
    public void onEventHappened(String string) {

        // This method called from doWork() method in WorkerClass      
        Log.d(TAG, string);
    }

}

Now you're ready to create other classes/activities/fragments that can implement this. And that's it!