Android网络编程之二:Okhttp Call封装

转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/54906978
本文出自:【Kevin.zhou的博客】

  Okhttp友好地提供了异步请求,但是它的回调是在访问的当前线程。由于Android不允许在主线程访问网络,所以返回的数据不能直接用来更新UI,那么是否可以进行一些封装使之在子线程访问回数据调到主线程呢?

Okhttp使用回顾

使用步骤:

  1. 获取OkHttpClient对象
  2. 创建Request对象
  3. 创建Call对象
  4. 调用call对象的execute(同步)发送请求、enqueue(异步)发送请求
  5. 获得Response对象当中的数据

OK按照使用步骤进行简单的使用

// 1. 获取OkHttpClient对象
OkHttpClient client = new OkHttpClient();
// 2. 创建Request对象
Request request = new Request.Builder()
        .url("http://123.57.31.11/androidnet/getJoke?id=7")
        .get()
        .build();
// 3. 创建Call对象
Call call = client.newCall(request);
// 4. 调用call对象的execute(同步)发送请求、enqueue(异步)发送请求
Log.d(TAG, "Thread id->" + Thread.currentThread().getId());
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "Thread id->" + Thread.currentThread().getId());
        // 5. 获得Response对象当中的数据
        String responseStr = response.body().string();
        Log.d(TAG, "responseStr: " + responseStr);
    }
});

Log信息如下:

D/MainActivity: Thread id->1
D/MainActivity: Thread id->162
D/MainActivity: responseStr: 女神今天过生日,刚才问我晚上有没有空,我心中暗喜难道她是要邀请我一起过生日,于是故作镇定的说:“有啊,怎么了?”然后她说:“太好了,今晚我生日聚会,很多朋友一起喝酒,你吃完晚饭来帮我们开车吧!”

可以看到创建请求的过程是在UI完成的,加入请求调度进行异步请求的返回结果是在非UI线程的。
  

封装分析

通过对Okhttp使用步骤的分解,是Call进行的异步请求调度的过程中由主线程转到子线程的,那么就要对Call进行封装。

Android网络编程之二:Okhttp Call封装_第1张图片

可以看到OkhttpCall为一个接口,其实在创建Call对象的时候是创建的Call接口的实现类RealCallOkHttpClientnewCall方法如下:

/**
 * Prepares the {@code request} to be executed at some point in the future.
 */
@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
}

那么我们就可以定义一个自己的Call,然后对okhttp3.Call进行包装,在enqueue(Callback callback)中进行修改,把结果调到主线程就可以啦~

撸代码

  1. 创建一个自己的OkHttpCall继承okhttp3.Call接口:

    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    public class OkHttpCall implements okhttp3.Call {
    }
  2. 实现抽象方法

    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    public class OkHttpCall implements okhttp3.Call {
    
        @Override
        public Request request() {
            return null;
        }
    
        @Override
        public Response execute() throws IOException {
            return null;
        }
    
        @Override
        public void enqueue(Callback callback) {
    
        }
    
        @Override
        public void cancel() {
    
        }
    
        @Override
        public boolean isExecuted() {
            return false;
        }
    
        @Override
        public boolean isCanceled() {
            return false;
        }
    
        @Override
        public okhttp3.Call clone() {
            return null;
        }
    }
  3. 注入Call

    由于是对Call进行包装,所以这里在构造方法中注入Call

    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    public class OkHttpCall implements okhttp3.Call {
    
        okhttp3.Call realCall;
    
        public OkHttpCall(okhttp3.Call call) {
            this.realCall = call;
        }
    
        // ... ...
    }
  4. 所有方法都交给Call去处理

    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    public class OkHttpCall implements okhttp3.Call {
    
        okhttp3.Call realCall;
    
        public OkHttpCall(okhttp3.Call call) {
            this.realCall = call;
        }
    
        @Override
        public Request request() {
            return realCall.request();
        }
    
        @Override
        public Response execute() throws IOException {
            return realCall.execute();
        }
    
        @Override
        public void enqueue(Callback callback) {
            // TODO 大干一场
        }
    
        @Override
        public void cancel() {
            realCall.cancel();
        }
    
        @Override
        public boolean isExecuted() {
            return realCall.isExecuted();
        }
    
        @Override
        public boolean isCanceled() {
            return realCall.isCanceled();
        }
    
        @Override
        public okhttp3.Call clone() {
            return realCall.clone();
        }
    }
    
  5. enqueue方法编写

    @Override
    public void enqueue(final Callback callback) {
        realCall.enqueue(new Callback() {
            @Override
            public void onFailure(final Call call, final IOException e) {
                // TODO 访问失败回调到主线程
            }
    
            @Override
            public void onResponse(final Call call, final Response response) throws IOException {
                // TODO 访问成功回调到主线程
            }
        });
    }

    费了那么大工夫,最主要的就是上面代码的两个TODO即怎样把访问结果回调到主线程去。

  6. 创建Handler帮助类

    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    
    public class MainThreadExecutor implements Executor {
    
        private Handler handler = new Handler(Looper.getMainLooper());
    
        private MainThreadExecutor() {
        }
    
        private static MainThreadExecutor sInstance = null;
    
        public static MainThreadExecutor getInstance() {
            if (sInstance == null) {
                synchronized (MainThreadExecutor.class) {
                    if (sInstance == null)
                        sInstance = new MainThreadExecutor();
                }
            }
            return sInstance;
        }
    
        @Override
        public void execute(Runnable command) {
            handler.post(command);
        }
    }

    这里主要是创建了一个Handler然后就可以调度到主线程啦~

  7. 访问结果回调到主线程

    @Override
    public void enqueue(final Callback callback) {
        realCall.enqueue(new Callback() {
            @Override
            public void onFailure(final Call call, final IOException e) {
                MainThreadExecutor.getInstance().execute(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(call, e);
                    }
                });
            }
    
            @Override
            public void onResponse(final Call call, final Response response) throws IOException {
                MainThreadExecutor.getInstance().execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            callback.onResponse(call, response);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

    OK,自此封装就完成了,下面为完整代码以及如何使用。

源码

  1. OkHttpCall

    package com.kevin.okhttp;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.Request;
    import okhttp3.Response;
    
    import java.io.IOException;
    
    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    public class OkHttpCall implements okhttp3.Call {
    
        okhttp3.Call realCall;
    
        public OkHttpCall(okhttp3.Call call) {
            this.realCall = call;
        }
    
        @Override
        public Request request() {
            return realCall.request();
        }
    
        @Override
        public Response execute() throws IOException {
            return realCall.execute();
        }
    
        @Override
        public void enqueue(final Callback callback) {
            realCall.enqueue(new Callback() {
                @Override
                public void onFailure(final Call call, final IOException e) {
                    MainThreadExecutor.getInstance().execute(new Runnable() {
                        @Override
                        public void run() {
                            callback.onFailure(call, e);
                        }
                    });
                }
    
                @Override
                public void onResponse(final Call call, final Response response) throws IOException {
                    MainThreadExecutor.getInstance().execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                callback.onResponse(call, response);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
    
        @Override
        public void cancel() {
            realCall.cancel();
        }
    
        @Override
        public boolean isExecuted() {
            return realCall.isExecuted();
        }
    
        @Override
        public boolean isCanceled() {
            return realCall.isCanceled();
        }
    
        @Override
        public okhttp3.Call clone() {
            return realCall.clone();
        }
    }
  2. MainThreadExecutor

    package com.kevin.okhttp;
    
    import android.os.Handler;
    import android.os.Looper;
    
    import java.util.concurrent.Executor;
    
    /**
     * Created by zhouwenkai on 2017/2/6.
     */
    
    public class MainThreadExecutor implements Executor {
    
        private Handler handler = new Handler(Looper.getMainLooper());
    
        private MainThreadExecutor() {
        }
    
        private static MainThreadExecutor sInstance = null;
    
        public static MainThreadExecutor getInstance() {
            if (sInstance == null) {
                synchronized (MainThreadExecutor.class) {
                    if (sInstance == null)
                        sInstance = new MainThreadExecutor();
                }
            }
            return sInstance;
        }
    
        @Override
        public void execute(Runnable command) {
            handler.post(command);
        }
    }

使用方法

  和我们之前的使用方式基本一致,只是对Call加了层包装,多说无益,上代码:

// 1. 获取OkHttpClient对象
OkHttpClient client = new OkHttpClient();
// 2. 创建Request对象
Request request = new Request.Builder()
        .url("http://123.57.31.11/androidnet/getJoke?id=7")
        .get()
        .build();
// 3. 创建Call对象
Call call = client.newCall(request);
// 4. 使用OkHttpCall对Call进行包装
OkHttpCall okhttpCall = new OkHttpCall(call);
// 5. 调用OkHttpCall对象的enqueue(异步)发送请求
okhttpCall.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // 6. 获得Response对象当中的数据
        String responseStr = response.body().string();
        Log.d(TAG, "responseStr: " + responseStr);
    }
});

  其实就是我们开始写的使用方法,只不过修改了如下两行代码:

// 4. 使用OkHttpCall对Call进行包装
OkHttpCall okHhttpCall = new OkHttpCall(call);
// 5. 调用OkHttpCall对象的enqueue(异步)发送请求
okHttpCall.enqueue(new Callback() {
    // ... ...
}

总结

  以上就实现了对okhttp3.Call的封装,我们自定义了一个OkHttpCall作为okhttp3.Call的包装类,在enqueue(Callback callback)的异步请求调度中把结果调到主线程中,方便以后操作。这种方式是不是有种耳目一新的感觉呢~

你可能感兴趣的:(Android)