Android volley封装实践其二

关于android的volley封装之前写过一篇文章,见链接(https://www.jianshu.com/p/1f09e91bee66)。这篇文章主要是换种方式进行封装,具体步骤如下所示。
1.创建Request,并设置相应的参数:

public class CommonJsonObjectRequest extends JsonObjectRequest {
    private String TAG = this.getClass().getSimpleName();
    /*
     * code=1:处理成功;
     */
    public static final int CODE_SUCCESS = 100;
    private Context mContext;
    private JSONObject mJsonRequest;

    public CommonJsonObjectRequest(Context context, int method, String url,
                                   JSONObject jsonRequest, Response.Listener listener,
                                   Response.ErrorListener errorListener) {
        super(method, url, jsonRequest, listener, errorListener);
        init(context, jsonRequest);
    }

    /**
     * @param context
     * @param url
     * @param jsonRequest
     * @param listener
     * @param errorListener
     */
    public CommonJsonObjectRequest(Context context, String url, JSONObject jsonRequest,
                                   Response.Listener listener, Response.ErrorListener errorListener) {
        super(url, jsonRequest, listener, errorListener);
        if (jsonRequest != null) {
            Log.d(TAG, jsonRequest.toString());
        }
        init(context, jsonRequest);
    }

    /**
     * @param context
     * @param jsonRequest
     */
    private void init(Context context, JSONObject jsonRequest) {
        this.mContext = context.getApplicationContext();
        this.mJsonRequest = jsonRequest;
        setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 0, 0));
    }

    @Override
    public Map getHeaders() throws AuthFailureError {
        Map headersMap = new HashMap<>();
        //do your business requirement
        return headersMap;
    }

}

所做的工作也很简单,去配置网络访问RetryPolicy,比如超时时间,最大的重试次数。例外也会根据业务要求在请求的头部加入token等标识。
2.通过工厂模式创建请求队列,volley内部会有两种构造方式,同步请求或者异步请求,通过设置ResponseDelivery 可以实现。

public interface ResponseDelivery {
    /**
     * Parses a response from the network or cache and delivers it.
     */
    public void postResponse(Request request, Response response);

    /**
     * Parses a response from the network or cache and delivers it. The provided
     * Runnable will be executed after delivery.
     */
    public void postResponse(Request request, Response response, Runnable runnable);

    /**
     * Posts an error for the given request.
     */
    public void postError(Request request, VolleyError error);
}

这个工厂的代码如下:

/**
 * 网络请求队列工厂类
 */
public class RequestQueueFactory {

    private static RequestQueue sRequestQueue;
    private static RequestQueue sAsynRequestQueue;

    private static int ASYN_QUEUE_THREAD_POOL_SIZE = 3;

    private RequestQueueFactory() {

    }

    /**
     * 获取默认RequestQueue,回调是同步到主线程的
     *
     * @param context
     * @return
     */
    public synchronized static RequestQueue getRequestQueue(Context context) {
        if (sRequestQueue == null) {
            OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
            OkHttpStack stack = new OkHttpStack(okHttpClient);
            sRequestQueue = Volley.newRequestQueue(context, stack);
        }
        return sRequestQueue;
    }

    /**
     * 获取异步RequestQueue,回调是在异步线程的
     *
     * @param context
     * @return
     */
    public synchronized static RequestQueue getAsynRequeQueueRespond(
            final Context context) {
        if (sAsynRequestQueue == null) {
            sAsynRequestQueue = getAsynRequeQueueRespond(context,
                    ASYN_QUEUE_THREAD_POOL_SIZE);
        }
        return sAsynRequestQueue;
    }

    private static RequestQueue getAsynRequeQueueRespond(final Context context,
                                                         int threadPoolSize) {
        File cacheDir = new File(context.getCacheDir(), "volley_asyn");
        OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        OkHttpStack stack = new OkHttpStack(okHttpClient);
        Network network = new BasicNetwork(stack);
        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir),
                network, threadPoolSize, new ExecutorDelivery(
                AsyncTask.SERIAL_EXECUTOR));
        queue.start();
        return queue;
    }

}

在代码中有这样两行代码:

 if (sRequestQueue == null) {
            OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
            OkHttpStack stack = new OkHttpStack(okHttpClient);
            sRequestQueue = Volley.newRequestQueue(context, stack);
        }

这里是使用了okhttpstack,如果不进行设置,内部默认的会设置一个stack;

  if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

okhttpstack类如下:

/**
 * 使用OKHttp作为底层的HttpStack
 */
public class OkHttpStack implements HttpStack {
    private final OkHttpClient client;

    public OkHttpStack(OkHttpClient client) {
        this.client = client;
    }

    private static HttpEntity entityFromOkHttpResponse(Response response) throws IOException {
        BasicHttpEntity entity = new BasicHttpEntity();
        ResponseBody body = response.body();

        entity.setContent(body.byteStream());
        entity.setContentLength(body.contentLength());
        entity.setContentEncoding(response.header("Content-Encoding"));

        if (body.contentType() != null) {
            entity.setContentType(body.contentType().type());
        }
        return entity;
    }

    @SuppressWarnings("deprecation")
    private static void setConnectionParametersForRequest
            (okhttp3.Request.Builder builder, Request request)
            throws IOException, AuthFailureError {
        switch (request.getMethod()) {
            case Request.Method.DEPRECATED_GET_OR_POST:
                byte[] postBody = request.getPostBody();
                if (postBody != null) {
                    builder.post(RequestBody.create
                            (MediaType.parse(request.getPostBodyContentType()), postBody));
                }
                break;

            case Request.Method.GET:
                builder.get();
                break;

            case Request.Method.DELETE:
                builder.delete();
                break;

            case Request.Method.POST:
                builder.post(createRequestBody(request));
                break;

            case Request.Method.PUT:
                builder.put(createRequestBody(request));
                break;

            case Request.Method.HEAD:
                builder.head();
                break;

            case Request.Method.OPTIONS:
                builder.method("OPTIONS", null);
                break;

            case Request.Method.TRACE:
                builder.method("TRACE", null);
                break;

            case Request.Method.PATCH:
                builder.patch(createRequestBody(request));
                break;

            default:
                throw new IllegalStateException("Unknown method type.");
        }
    }

    private static RequestBody createRequestBody(Request request) throws AuthFailureError {
        final byte[] body = request.getBody();
        if (body == null) return null;

        return RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
    }

    private static ProtocolVersion parseProtocol(final Protocol protocol) {
        switch (protocol) {
            case HTTP_1_0:
                return new ProtocolVersion("HTTP", 1, 0);
            case HTTP_1_1:
                return new ProtocolVersion("HTTP", 1, 1);
            case SPDY_3:
                return new ProtocolVersion("SPDY", 3, 1);
            case HTTP_2:
                return new ProtocolVersion("HTTP", 2, 0);
        }

        throw new IllegalAccessError("Unkwown protocol");
    }

    @Override
    public HttpResponse performRequest(Request request, Map additionalHeaders)
            throws IOException, AuthFailureError {
        int timeoutMs = request.getTimeoutMs();
        OkHttpClient client = this.client.newBuilder()
                .readTimeout(timeoutMs, TimeUnit.MILLISECONDS)
                .connectTimeout(timeoutMs, TimeUnit.MILLISECONDS)
                .writeTimeout(timeoutMs, TimeUnit.MILLISECONDS)
                .build();

        okhttp3.Request.Builder okHttpRequestBuilder = new okhttp3.Request.Builder();
        Map headers = request.getHeaders();

        for (Map.Entry entry : headers.entrySet()) {
            okHttpRequestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

        for (Map.Entry entry : additionalHeaders.entrySet()) {
            okHttpRequestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

//        for (final String name : headers.keySet()) {   //entrySet的遍历效率比keySet高上一个遍历元素的速度
//            okHttpRequestBuilder.addHeader(name, headers.get(name));
//        }

//        for (final String name : additionalHeaders.keySet()) {
//            okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
//        }

        setConnectionParametersForRequest(okHttpRequestBuilder, request);

        okhttp3.Request okhttp3Request = okHttpRequestBuilder.url(request.getUrl()).build();
        Response okHttpResponse = client.newCall(okhttp3Request).execute();

        StatusLine responseStatus = new BasicStatusLine
                (
                        parseProtocol(okHttpResponse.protocol()),
                        okHttpResponse.code(),
                        okHttpResponse.message()
                );
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        response.setEntity(entityFromOkHttpResponse(okHttpResponse));

        Headers responseHeaders = okHttpResponse.headers();
        for (int i = 0, len = responseHeaders.size(); i < len; i++) {
            final String name = responseHeaders.name(i), value = responseHeaders.value(i);
            if (name != null) {
                response.addHeader(new BasicHeader(name, value));
            }
        }
        return response;
    }
}

其中核心代码在performRequest方法中。
3.封装基类。基类使用abstract会更灵活,子类可以选择性的重写方法。

/**
 * 网络处理基类
 */
public abstract class BaseNetModel {

    protected RequestQueue requestQueue;
    protected Context context;
    protected Object mTag;

    protected BaseNetModel(Context context) {
        this.context = context.getApplicationContext();
        requestQueue = RequestQueueFactory.getAsynRequeQueueRespond(this.context);
    }

    protected BaseNetModel(Context context, boolean isAsyn) {
        this.context = context.getApplicationContext();
        requestQueue = isAsyn ? RequestQueueFactory.getAsynRequeQueueRespond(this.context)
                : RequestQueueFactory.getRequestQueue(context);
    }

    /**
     * 推荐用页面ClassName+时间戳
     *
     * @param tag
     */
    public void setTag(Object tag) {
        this.mTag = tag;
    }

    public void destroy() {
        if (mTag != null) {
            cancelTaskByTag(mTag);
        }
        requestQueue = null;
        context = null;
    }

    public void cancelTaskByTag(Object tag) {
        if (requestQueue != null) {
            requestQueue.cancelAll(tag);
        }
    }


    public void addRequest(String path, JSONObject jsonRequest, Response.Listener listener, Response.ErrorListener errorListener) {
        addRequest(path, true, jsonRequest, listener, errorListener);
    }

    /**
     * @param path          不带域名的接口路径
     * @param withTag       是否带上页面的tag
     * @param jsonRequest
     * @param listener
     * @param errorListener
     */
    public void addRequest(String path, boolean withTag, JSONObject jsonRequest, Response.Listener listener, Response.ErrorListener errorListener) {
        addRequestUrl(path, withTag, jsonRequest, listener, errorListener);
    }

    /**
     * @param url           完整接口地址
     * @param withTag
     * @param jsonRequest
     * @param listener
     * @param errorListener
     */
    public void addRequestUrl(String url, boolean withTag, JSONObject jsonRequest, Response.Listener listener, Response.ErrorListener errorListener) {
        if (jsonRequest == null) {
            jsonRequest = new JSONObject();
        }
        CommonJsonObjectRequest request = new CommonJsonObjectRequest(context, url, jsonRequest, listener, errorListener);
        if (withTag && mTag != null) {
            request.setTag(mTag);
        }
        requestQueue.add(request);
    }

}

4.逻辑封装。
这里选用的是一个新闻的接口,这种接口可以在聚合数据上申请,有的收费,有的免费。

public class NewsModel extends BaseNetModel {
    public NewsModel(Context context) {
        super(context);
    }

    public NewsModel(Context context, boolean isAsyn) {
        super(context, isAsyn);
    }

    public void getInfo(Response.Listener listener, Response.ErrorListener errorListener) throws Exception {
        JSONObject jsonObject = new JSONObject();
        addRequest(INetConstant.NEWS, jsonObject, listener, errorListener);
    }
}

接口的地址为:(http://v.juhe.cn/toutiao/index?type=&key=b2f8e4aeacfa310cabfadd5189bbe4d5)
5.开始使用。

 NewsModel newsModel = new NewsModel(getActivity());
        try {
            newsModel.getInfo(new Response.Listener() {
                @Override
                public void onResponse(final JSONObject response) {
                    ThreadUtils.runInUIThread(new Runnable() {
                        @Override
                        public void run() {
                            News news = new Gson().fromJson(response.toString(), News.class);
                            mAdapter.setData(news.getResult().getData());
                        }
                    });
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

最后放一张图:


Android volley封装实践其二_第1张图片
图片发自App

分享结束,代码在[github] (https://github.com/daydaydate/sample)。感谢您的阅读。

你可能感兴趣的:(Android volley封装实践其二)