Wednesday, March 11, 2015

MainThreadCallback for OkHttp 2.+

When working with OkHttp's Call, the results are delivered on the background Thread. Since I usually need to have them delivered to the main Thread, I have made this simple class to publish my results there. As you can see, the implementation is heavily influenced by Square's Retrofit.

Basically, what it does, is to check the Response, get its body and post it as success(). If anything goes wrong, the failure() is called passing you a CallError, which simply encapsulates possible Exception, Request and a type of the failure.

public abstract class MainThreadCallback implements Callback {

    private final Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public final void onFailure(final Request request, final IOException e) {
        callFailure(CallError.networkError(request, e));
    }

    @Override
    public final void onResponse(final Response response) throws IOException {
        if (response.isSuccessful() && response.body() != null) {
            try {
                final String body = response.body().string();
                mHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        success(body);
                    }
                });
            } catch (final IOException e) {
                callFailure(CallError.networkError(response.request(), e));
            }
        } else {
            callFailure(CallError.httpError(response.request()));
        }
    }

    private void callFailure(final CallError error) {
        mHandler.post(new Runnable() {

            @Override
            public void run() {
                failure(error);
            }
        });
    }

    public abstract void success(String responseBody);

    public abstract void failure(CallError error);

}
public class CallError extends RuntimeException {

    public static CallError networkError(Request response, IOException exception) {
        return new CallError(response, Kind.NETWORK, exception);
    }

    public static CallError httpError(Request response) {
        return new CallError(response, Kind.HTTP, null);
    }

    public enum Kind {
        /**
         * An {@link java.io.IOException} occurred while communicating to the server.
         */
        NETWORK,
        /**
         * A non-200 HTTP status code was received from the server.
         */
        HTTP
    }

    private final Request request;
    private final Kind kind;

    CallError(Request request, Kind kind, Throwable throwable) {
        super(throwable);
        this.request = request;
        this.kind = kind;
    }

    public Request getRequest() {
        return request;
    }

    public Kind getKind() {
        return kind;
    }
}

2 comments:

  1. Hello, can u share a usage - sample please ?

    ReplyDelete
  2. Hi, consider following example. Normal Callback crashes with "android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.", while the MainThreadCallback executes successfully.

    ReplyDelete