Otto + Retrofit – An elegant solution for Web Requests

The Problem

Retrofit is a fantastic library but can generate some extra boiler plate code. In this example I am going to set two server calls (GET users and GET posts), in order to exemplify my concerns.

First we need to define a RestAdapter to execute requests.

public class HttpRequestController {

    private static final String API_URL = "http://jsonplaceholder.typicode.com";
    private ApiRequests request;

    public HttpRequestController() {
        RestAdapter.Builder builder = new RestAdapter.Builder();
        builder.setEndpoint(API_URL);
        builder.setLogLevel(RestAdapter.LogLevel.FULL);
        RestAdapter controller = builder.build();
        request = controller.create(ApiRequests.class);
    }

    public void getPosts(Callback<List<Post>> cb){
        request.posts(cb);
    }

    public void getUsers(Callback<List<User>> cb){
        request.users(cb);
    }

}

And set the requests verbs and callbacks via an interface.

public interface ApiRequests {

    @GET("/posts")
    void posts(Callback<List<Post>> cb);

    @GET("/users")
    void users(Callback<List<User>> cb);

}

Now we can set the callbacks in the main class and invoke the server requests.

    private Callback<List<Post>> postCallback = 
           new Callback<List<Post>>() {
        @Override
        public void success(List<Post> postsList, Response response) {
            String postsText = "";
            for (Post post: postsList){
                postsText = postsText.concat(
                               post.getId()+
                               ": "+post.getTitle()+"\n");
            }
            postsView.setText(postsText);
        }

        @Override
        public void failure(RetrofitError error) {
            postsView.setText(error.getMessage());
        }
    };

    private Callback<List<User>> usersCallback = 
          new Callback<List<User>>() {

        @Override
        public void success(List<User> usersList, Response response) {
            String userText = "";
            for (User user: usersList){
                userText = userText.concat(
                        user.getId()+" : "+
                        user.getUsername()+" aka "+user.getName()
                                +"\n");
            }
            postsView.setText(userText);
        }

        @Override
        public void failure(RetrofitError error) {
            postsView.setText(error.getMessage());
        }
        
    };
controller.getPosts(postCallback);
controller.getUsers(usersCallback);

Personally I don’t like to define Callbacks this way because it affects the elegance of the code. This code works fine and this is a valid pattern but imagine having 3, 4 or 5 of these in the beginning of your class. It really affects code readability and you need to set a Callback each time you want to make a request in a particular class. You keep repeating the same code for each class.

The Solution

After having to deal with lots of these I came up with a solution using Otto that allows a much cleaner design.

First I created something I called Composed Object (CO). The CO has 3 components:

  • Request – data to be sent to the server
  • Callback – callback to handle server responses
  • Event – event to be invoked when the callback is received and processed
public class GetUsers {

    public static final class Request {}

    public static final class Callback 
          implements retrofit.Callback<Response response> {

        @Override
        public void success(Response response, 
             Response retrofitResponse) {}

        @Override
        public void failure(RetrofitError error) {}

    }

    // Otto Event
    public static final class Event {}
}

This object contains all the information necessary to create and process a request. The first part Request is the object that is going to be converted to JSON by Retrofit and embedded in the BODY during POST calls. The Callback is the same we defined previously in the main class. The Event is the object that will be delivered using Otto event bus.

A complete CO would look like this:

public final class GetUsers {

    public static final class Callback implements 
              retrofit.Callback<List<User>> {

        @Override
        public void success(List<User> usersList, 
              Response retrofitResponse) {
            String text = "";
            for (User user : usersList) {
                text = text.concat(
                        user.getId() + " : " +
                        user.getUsername() + " aka " + user.getName()
                        + "\n");
            }
            BusManager.post(new Event(text));
        }

        @Override
        public void failure(RetrofitError error) {
            BusManager.post(new RetrofitErrorEvent(error));
        }

    }

    // Otto Event
    public static final class Event {

        private final String text;

        public Event(String text) {
            this.text = text;
        }

        public String getText() {
            return text;
        }
    }
}

After having the CO we need to update the RestAdapter.

  public void getPosts(){
        // The result is going to be delivered via an event so the 
        // callback can be defined here.
        request.posts(new GetPosts.Callback());
    }

    public void getUsers(){
        request.users(new GetUsers.Callback());
    }

And there is no need to provide a callback while making the request.

controller.getPosts();
controller.getUsers();

This pattern gives a much cleaner MainActivity without the extra callbacks. Using Otto Event Bus we subscribe to the event we want to listen to and that’s it.

    // Otto Events
@Subscribe
public void onGetPostsEvent(GetPosts.Event event){
    textView.setText(event.getText());
}

@Subscribe
public void onGetUserEvent(GetUsers.Event event){
     textView.setText(event.getText());
}

@Subscribe
public void onRetrofitErrorEvent(RetrofitErrorEvent event){
     textView.setText(event.getError().getMessage());
}

Without this pattern, every time you need to make a server request you need to define a callback, often the same callback, over and over again. Now scale it for a complete solution and it is easy to imagine the amount of extra code needed to deal with server requests. Using this solution you only need to define the Composed Object once, make the request and listen for the events you want. It also prevents you to define a public void failure(RetrofitError error); for each request. You subscribe for the RetrofitErrorEvent and you can have a central point to process all Retrofit Errors.

The source code can be found here and provides two modules showing each approach.

Libraries

Retrofit

Recently I started using Retrofit and I am very pleased with it. It does all the REST hard work for me and uses a system of callbacks to retrieve the received data.

Otto

I have been using Otto for a long time now. It allows me to have a cleaner code avoiding to implement multiple callback interfaces. Otto is an event bus that allows to listen for events using annotations.

Android: hide action bar while view load.

Setting the properties “windowNoTitle” to true on your theme  will hide the ActionBar  but when you do “getSupportActionBar” in code you get a “NullPointerException”.

So the trick is to use two different themes both extending parent=”Theme.AppCompat.Light”

You would do something like

 <style name="AppThemeNoBar" parent="Theme.AppCompat.Light">
        <item name="android:windowNoTitle">true</item>
 </style>

 <style name="AppThemeBar" parent="Theme.AppCompat.Light">
        <item name="android:windowNoTitle">false</item>
 </style>

Now you can set the AppThemeNoBar as the theme for the application and AppThemeBar for the activities where you want to show the action bar.

This way, when you have an application loading a view, you will only see a blank view instead of the view with the default ActionBar.

Due to some odd behaviour on versions < 11,  you need to add

if (Build.VERSION.SDK_INT < 11){
    getSupportActionBar().hide();
}

in the activities where you don’t want the ActionBar.

Access private methods in Android using Roboletric.

I wanted to test a private method I had wrote in an class extending an Android Service. Using PowerMock this is easy to do but Roboletric does not support access to private methods.
After some research I was able to complete the test using a reflection.

Let’s say that I wanted to access a private method called isConnected() in a class named ConnectionService().

First I created a shadow object called ShadowConnectionService. This class was very simple and it was used to provide access to the real ConnectionService object.

@Implements(ConnectionService.class)
public class ShadowConnectionService {

    @RealObject
    private ConnectionService connectionService;

    public ConnectionService getconnectionService() {
        return connectionService;
    }

    public void setConnectionService
            (ConnectionService connectionService) {
        this.connectionService = connectionService;
    }
}

Then in the test file I use the Shadow to create an object I could test and got a reference for the real connectionService object.

    private ShadowConnectionService shadowConnectionService;
    private ConnectionService connectionService;


    @Before
    public void startService() {
        shadowConnectionService = new ShadowConnectionService();
        connectionService = shadowConnectionService.getconnectionService();
    }

And now the test

    @Test
    public void ShouldBeConnected() {

        // Act.
        boolean isConnected = invokeMethod("isConnected", device);
        // Verify
        assertThat(isDevice).isEqualTo(expectedResult);
    }

    private Boolean invokeMethod(String methodToExecute, BluetoothDevice device) {

        Class x = ConnectionService.class;
        Method[] methods = x.getDeclaredMethods();

        for (Method m :methods){
            if (m.getName().equals(methodToExecute)) {
                try {
                    m.setAccessible(true);
                    return (Boolean) m.invoke(connectionService, new Object[]{device});
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

And that’s it. Using a Roboletric shadow object and a little reflection you can test private methods in Android classes.