久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5201|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

商城開發(fā)筆記-06-OkHttp的使用以及簡單封裝

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:109770 發(fā)表于 2016-3-22 17:20 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
一、Android中網(wǎng)絡(luò)請求的進化

       Android開發(fā)中網(wǎng)絡(luò)編程是必不可少的,不接入互聯(lián)網(wǎng)的APP就沒有盈利可言。廢話不多說了,下面請看Android中網(wǎng)絡(luò)請求的進化圖:
                              
       HttpURLConnectionApache HTTP ClientVolley到現(xiàn)在的OKHttp,可謂天外有天,人外有人。為什么OKHttp會這么火呢,相信下面的介紹會告訴你答案。


二、OKHttp的簡介

首先,給出OKHttp的項目地址:https://github.com/square/okhttp

       Android為我們提供了兩種HTTP交互的方式: HttpURLConnection ApacheHTTP Client,雖然兩者都支持HTTPS,流的上傳和下載,配置超時,IPv6和連接池,已足夠滿足我們各種HTTP請求的需求。但更高效的使用HTTP可以讓您的應(yīng)用運行更快、更節(jié)省流量。而OkHttp庫就是為此而生。
OkHttp是一個高效的HTTP:
1.支持 SPDY ,共享同一個Socket來處理同一個服務(wù)器的所有請求
2.如果SPDY不可用,則通過連接池來減少請求延時
3.無縫的支持GZIP來減少數(shù)據(jù)流量
4. 緩存響應(yīng)數(shù)據(jù)來減少重復(fù)的網(wǎng)絡(luò)請求
·        一般的get請求
·        一般的post請求
·        基于Http的文件上傳
·        文件下載
·        加載圖片
·        支持請求回調(diào),直接返回對象、對象集合
·        支持session的保持


       OkHttp會從很多常用的連接問題中自動恢復(fù)。如果您的服務(wù)器配置了多個IP地址,當(dāng)?shù)谝粋IP連接失敗的時候,會自動嘗試下一個IPOkHttp還處理了代理服務(wù)器問題和SSL握手失敗問題。(并發(fā))
       使用 OkHttp 無需重寫您程序中的網(wǎng)絡(luò)代碼。OkHttp實現(xiàn)了幾乎和java.net.HttpURLConnection一樣的API。如果您用了 Apache HttpClient,則OkHttp也提供了一個對應(yīng)的okhttp-apache 模塊。
       從上面的簡單介紹中可以知道,雖然在編程上面并不會簡潔很多,但是OKHttp內(nèi)部的一些功能能夠幫助我們自動完成一些很復(fù)雜的操作,筆者個人認(rèn)為最大的賣點就是大大節(jié)省用戶的流量。


三、OKHttp的基本使用
1、在Gradle中引入CardView的依賴庫。
compile 'com.squareup.okhttp:okhttp:2.7.2'
2OKHttp在使用之前,首先要了解下面幾個比較核心的類以及它的功能。
l        OkHttpClient客戶端對象
l        Request是OkHttp中訪問的請求,Post請求中需要包含RequestBody
l        Builder是輔助類,用于生產(chǎn)對象
l        Response即OkHttp中的響應(yīng),響應(yīng)中可以得到返回是否成功,返回數(shù)據(jù)
l        MediaType  數(shù)據(jù)類型,用來表明是JSON等一系列格式
l        RequestBody請求數(shù)據(jù),在Post請求中用到
l        client.newCall(request).execute()是同步的請求方法
l        client.newCall(request).enqueue(CallbackcallBack)是異步的請求方法,但是Callback里面的代碼是執(zhí)行在子線程的,因此不能更新UI。

3OKHttp的基本使用步驟(以POST方式從服務(wù)器取JSON數(shù)據(jù)為例)
l        創(chuàng)建OkHttpClient對象,官方文檔要求我們最好使用單例模式,在后文對OKHttp進行封裝的時候會提到。
l        如果是post請求的話,需要通過FormEncodingBuilder創(chuàng)建RequestBody對象,指定需要post傳進去的參數(shù)。get請求則不用。
l        創(chuàng)建Request對象,這個對象是請求對象,需要指定URL。post請求的時候需要指定RequestBody對象,get請求則不用。
l        調(diào)用OkHttpClient的newCall方法,把Request對象傳進去,然后執(zhí)行execute或者enqueue方法,兩者的區(qū)別在上文已提到。在CallBack中的onResponse方法就可以做你需要做的事。onResponse回調(diào)的參數(shù)是response,一般情況下,比如我們希望獲得返回的字符串,可以通過response.body().string()獲取;如果希望獲得返回的二進制字節(jié)數(shù)組,則調(diào)用response.body().bytes();如果你想拿到返回的inputStream,則調(diào)用response.body().byteStream()看到這,你可能會奇怪,竟然還能拿到返回的inputStream,看到這個最起碼能意識到一點,這里支持大文件下載,有inputStream我們就可以通過IO的方式寫文件。不過也說明一個問題,這個onResponse執(zhí)行的線程并不是UI線程。的確是的,如果你希望操作控件,還是需要使用handler等。

OkHttpClientclient = new OkHttpClient();
RequestBodybody = new FormEncodingBuilder()
        .add("type", "1")
        .build();
Requestrequest = new Request.Builder()
        .url(Constants.URL_BANNER)
        .post(body)
        .build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Request request, IOException e) {
    }
    @Override
    public void onResponse(Response response) throws IOException{
        if (response.isSuccessful()) {
            android.os.Message msg = new Message();
            msg.what = 1;
            msg.obj = response.body().string();
            mHandler.sendMessage(msg);
        }
    }
});
       這里只是一個簡單post請求,從服務(wù)器獲取數(shù)據(jù)的介紹,至于get請求只不過是去掉RequestBody對象而已。至于如何向服務(wù)器提交數(shù)據(jù),可以在熟悉上面的基本用法之后查閱官方的WIKIGitHub的介紹文檔)。另外楠妹妹也推薦下面這一篇文章,http://blog.csdn.net/lmj623565791/article/details/47911083
四、OKHttp的簡單封裝
       回顧上面的代碼,試想一下如果每次請求都寫這么多重復(fù)代碼,這樣會嚴(yán)重降低開發(fā)效率,因此需要對OKHttp進行封裝。對代碼進行封裝是我們最為面向?qū)ο蟪绦騿T的基本素養(yǎng),減少重復(fù)代碼,降低維護難度以及成本。
      
       GitHub上也有對OKHttp進行過封裝,叫做OKHttpUtils。不過這里我們自己動手,一起來學(xué)習(xí)一下如何進行封裝。具體的注意點有下面幾點:
1、首先,OKHttp官方要求我們最好用單例模式去使用OKHttpClient類的,因此我們自定義一個OKHttpHelper類,并且使用單例模式。
2、對get以及post方法進行封裝,主要的思想是把共同的代碼抽取出來,例如代碼中被抽取出來的request方法。
3、對外公開一些靜態(tài)方法,包括getpost方法等。
4Callback基類,對OKHttp的回調(diào)進行封裝。這個類用里面有一個type,是方便回調(diào)中使用GsonJSON進行解析的封裝。使用Callback的時候只需要在泛型中傳入類似DataList<Data>即可以方便地使用JSON
5、由于原來的回調(diào)不在主線程,因此我們需要使用Handler來將回調(diào)放入主線程。
其余的可以參照代碼,有詳細(xì)注釋。
import android.os.Handler;
import android.os.Looper;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 這個類用來輔助OKHttp
*/
public class OkHttpHelper {
    /**
     * 采用單例模式使用OkHttpClient
     */
    private static OkHttpHelper mOkHttpHelperInstance;
    private static OkHttpClient mClientInstance;
    private Handler mHandler;
    private Gson mGson;
    /**
     * 單例模式,私有構(gòu)造函數(shù),構(gòu)造函數(shù)里面進行一些初始化
     */
    private OkHttpHelper() {
        mClientInstance = newOkHttpClient();
        mClientInstance.setConnectTimeout(10, TimeUnit.SECONDS);
        mClientInstance.setReadTimeout(10, TimeUnit.SECONDS);
        mClientInstance.setWriteTimeout(30, TimeUnit.SECONDS);
        mGson = new Gson();
        mHandler = new Handler(Looper.getMainLooper());
    }
    /**
     * 獲取實例
     *
     * @return
     */
    public static OkHttpHelper getinstance() {
        if (mOkHttpHelperInstance == null) {
            synchronized (OkHttpHelper.class) {
                if (mOkHttpHelperInstance == null) {
                    mOkHttpHelperInstance = newOkHttpHelper();
                }
            }
        }
        return mOkHttpHelperInstance;
    }
    /**
     * 封裝一個request方法,不管post或者get方法中都會用到
     */
    public void request(final Request request, final BaseCallback callback) {
        //在請求之前所做的事,比如彈出對話框等
        callback.onRequestBefore();
        mClientInstance.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                //返回失敗
                callbackFailure(request, callback, e);
            }
            @Override
            public void onResponse(Response response) throws IOException{
                if (response.isSuccessful()) {
                    //返回成功回調(diào)
                    String resString = response.body().string();
                    if (callback.mType == String.class) {
                        //如果我們需要返回String類型
                        callbackSuccess(response, resString, callback);
                    } else {
                        //如果返回的是其他類型,則利用Gson去解析
                        try {
                            Object o = mGson.fromJson(resString, callback.mType);
                            callbackSuccess(response, o, callback);
                        } catch (JsonParseException e) {
                            e.printStackTrace();
                            callbackError(response, callback, e);
                        }
                    }
                } else {
                    //返回錯誤
                    callbackError(response, callback, null);
                }
            }
        });
    }
    /**
     * 在主線程中執(zhí)行的回調(diào)
     *
     * @param response
     * @param resString
     * @param callback
     */
    private void callbackSuccess(final Response response, final Object o, finalBaseCallback callback) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onSuccess(response, o);
            }
        });
    }
    /**
     * 在主線程中執(zhí)行的回調(diào)
     * @param response
     * @param callback
     * @param e
     */
    private void callbackError(final Response response, final BaseCallback callback, final Exception e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onError(response, response.code(), e);
            }
        });
    }
    /**
     * 在主線程中執(zhí)行的回調(diào)
     * @param request
     * @param callback
     * @param e
     */
    private void callbackFailure(final Request request, final BaseCallback callback, final Exception e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onFailure(request, e);
            }
        });
    }
    /**
     * 對外公開的get方法
     *
     * @param url
     * @param callback
     */
    public void get(String url, BaseCallback callback) {
        Request request = buildRequest(url, null,HttpMethodType.GET);
        request(request, callback);
    }
    /**
     * 對外公開的post方法
     *
     * @param url
     * @param params
     * @param callback
     */
    public void post(String url, Map<String, String> params, BaseCallback callback) {
        Request request = buildRequest(url, params, HttpMethodType.POST);
        request(request, callback);
    }
    /**
     * 構(gòu)建請求對象
     *
     * @param url
     * @param params
     * @param type
     * @return
     */
    private Request buildRequest(String url, Map<String, String> params, HttpMethodType type) {
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        if (type == HttpMethodType.GET) {
            builder.get();
        } else if (type == HttpMethodType.POST) {
            builder.post(buildRequestBody(params));
        }
        return builder.build();
    }
    /**
     * 通過Map的鍵值對構(gòu)建請求對象的body
     *
     * @param params
     * @return
     */
    private RequestBody buildRequestBody(Map<String, String> params) {
        FormEncodingBuilder builder = newFormEncodingBuilder();
        if (params != null) {
            for (Map.Entry<String, String> entity : params.entrySet()) {
                builder.add(entity.getKey(), entity.getValue());
            }
        }
        return builder.build();
    }
    /**
     * 這個枚舉用于指明是哪一種提交方式
     */
    enum HttpMethodType {
        GET,
        POST
    }
}
package com.nan.cnshop.http;
import com.google.gson.internal.$Gson$Types;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 基本的回調(diào)
*/
public abstract class BaseCallback<T> {
    /**
     * type用于方便JSON的解析
     */
    public Type mType;
    /**
     * type轉(zhuǎn)換成對應(yīng)的類,這里不用看明白也行。
     *
     * @param subclass
     * @return
     */
    static Type getSuperclassTypeParameter(Class<?> subclass) {
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missingtype parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
    }
    /**
     * 構(gòu)造的時候獲得typeclass
     */
    public BaseCallback() {
        mType = getSuperclassTypeParameter(getClass());
    }
    /**
     * 請求之前調(diào)用
     */
    public abstract void onRequestBefore();
    /**
     * 請求失敗調(diào)用(網(wǎng)絡(luò)問題)
     *
     * @param request
     * @param e
     */
    public abstract void onFailure(Request request, Exception e);
    /**
     * 請求成功而且沒有錯誤的時候調(diào)用
     *
     * @param response
     * @param t
     */
    public abstract void onSuccess(Response response, T t);
    /**
     * 請求成功但是有錯誤的時候調(diào)用,例如Gson解析錯誤等
     *
     * @param response
     * @param errorCode
     *@param e
     */
    public abstract void onError(Response response, int errorCode, Exception e);
}
五、OKHttp封裝之后的使用

       如下面的代碼所示。首先得到OkHttpHelper的單例,然后調(diào)用get方法就可以了。由于繼承了Gson,因此需要在BaseCallback的泛型中傳入JSON對應(yīng)的數(shù)據(jù)類型,筆者這里是List<Banner>。最后在onSuccess方法中做我們想要做的事情就可以了。

mHttpHelper=OkHttpHelper.getinstance();
mHttpHelper.get(Constants.URL_BANNER, new BaseCallback<List<Banner>>() {
    @Override
    public void onRequestBefore() {
    }
    @Override
    public void onFailure(Request request, Exception e) {
    }
    @Override
    public void onSuccess(Response response, List<Banner> banners) {
        initBanners(banners);
    }
    @Override
    public void onError(Response response, int errorCode, Exception e) {
    }
});

       是不是覺得封裝之后OKHttp的使用變得很簡單呢,這就是封裝的強大之處,好了今天的筆記到此為止,明天見O(_)O~~

       PS:這里只介紹了OKHttpgetpost使用介紹,其余的使用例如文件下載上傳以及對應(yīng)的代碼封裝請自己去完成~\(≧▽≦)/~啦啦啦。


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:116389 發(fā)表于 2016-5-21 11:39 | 只看該作者
搶沙發(fā),樓下做板凳
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产区免费视频 | 国产一区二区三区在线观看免费 | 免费在线成人 | 久久久久久久一区二区三区 | 午夜精品一区二区三区在线观看 | 欧美色综合一区二区三区 | 91久久精品一区 | 国产一级免费视频 | 中文字幕一区二区三区在线观看 | 久久久久久国产精品 | 国产精品有限公司 | 久久男人 | 精品二区| 久久99蜜桃综合影院免费观看 | 人人做人人澡人人爽欧美 | 天天射网站| 成人免费久久 | a久久| 国产精品激情小视频 | 中文字幕日韩欧美 | 午夜影院免费体验区 | 久久久久久久久久久一区二区 | 9久9久 | 秋霞av国产精品一区 | 久久国产精品偷 | 国产日韩电影 | 亚洲 欧美 在线 一区 | 国产午夜三级一区二区三 | 欧美在线观看一区二区 | 免费亚洲婷婷 | 日韩精品一区二区三区在线 | 国产精品高潮呻吟久久 | 91麻豆精品国产91久久久久久久久 | 色偷偷噜噜噜亚洲男人 | 欧美成人精品一区二区三区 | 国产精品无码久久久久 | 成人av片在线观看 | 黄色三级免费网站 | 黄色毛片大全 | 99色播 | 精品成人在线视频 |