Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android OkHttp框架解析

Android OkHttp框架解析

編輯:關於Android編程

Okhttp是由Sqare公司開發的開源網絡訪問庫,是目前比較火的網絡框架, 它處理了很多網絡疑難雜症:會從很多常用的連接問題中自動恢復。如果你的服務器配置了多個IP地址,當第一個IP連接失敗的時候,OkHttp會自動嘗試下一個IP,此外OkHttp還處理了代理服務器問題和SSL握手失敗問題。
首先介紹下OkHttp的簡單使用,主要包含:

同步/異步get請求 同步/異步post請求 基於Http的文件上傳 文件下載 加載圖片 支持請求回調,直接返回對象、對象集合 支持session的保持

使用前准備

Eclipse的用戶,下載最新的okhttp jar包,導入工程。同時okhttp內部依賴okio,所以別忘了同時導入okio jar包。
添加網絡訪問權限

OkHttp3用法

1. okHttp網絡請求之Get/Post請求

1.異步GET請求
最簡單的GET請求

private void getAsynHttp() {
        OkHttpClient mOkHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                showlog(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplication(), str, Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }

基本的步驟很簡單,就是創建OkHttpClient、Request和Call,最後調用Call的enqueue()方法。但是每次這麼寫肯定是很麻煩,肯定是要進行封裝的。需要注意的是onResponse回調並不是在UI線程。
注:onResponse回調的參數是response,一般情況下,比如我們希望獲得返回的字符串,可以通過response.body().string()獲取;如果希望獲得返回的二進制字節數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調用response.body().byteStream()。

2.同步GET請求
同步Get請求和異步調用區別就是調用了call的execute()方法。

 private String getSyncHttp() throws IOException{
        OkHttpClient mOkHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .build();
        Call call = mOkHttpClient.newCall(request);
        Response mResponse=call.execute();
        if (mResponse.isSuccessful()) {
            return mResponse.body().string();
        } else {
            throw new IOException("Unexpected code " + mResponse);
        }
   }

注意同步GET請求的調用必須放在子線程中執行,不然會報NetworkOnMainThreadException。

3.異步POST請求
post與get不同的就是要創建RequestBody並傳進Request中,同樣onResponse回調不是在UI線程。

private void postAsynHttp() {
        OkHttpClient mOkHttpClient = new OkHttpClient();
        RequestBody formBody = new FormBody.Builder()
                .add("topicId", "1002")
                .add("maxReply", "-1")
                .add("reqApp", "1")
                .build();

        Request request = new Request.Builder()
                .url("http://61.129.89.191/SoarAPI/api/SoarTopic")
                .post(formBody)
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                showlog(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    } 

2. okHttp網絡請求之文件上傳下載

1.異步上傳文件
上傳文件本身也是一個POST請求,首先定義上傳文件類型:

public final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");

將sdcard根目錄的demo.txt文件上傳到服務器上:

   private void postAsynFile() {
       OkHttpClient mOkHttpClient=new OkHttpClient();
       File file = new File("/sdcard/demo.txt");
       Request request = new Request.Builder()
               .url("https://api.github.com/markdown/raw")
               .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
               .build();

       mOkHttpClient.newCall(request).enqueue(new Callback() {
               @Override
               public void onFailure(Call call, IOException e) {
                   showlog(e.getMessage());
               }

               @Override
               public void onResponse(Call call, Response response) throws IOException {
                   showlog(response.body().string());
               }
           });
       }

當然如果想要改為同步的上傳文件只要調用 mOkHttpClient.newCall(request).execute()就可以了。
在demo.txt文件中有一行字“測試OkHttp異步上傳”我們運行程序點擊發送文件按鈕,最終請求網絡返回的結果就是我們txt文件中的內容 :
這裡寫圖片描述

當然不要忘了添加如下權限:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">

2.異步下載圖片
下載圖片本身也是一個GET請求

private void getAsynFile() {
       OkHttpClient mOkHttpClient = new OkHttpClient();
       Request request = new Request.Builder()
               .url("http://img.my.csdn.net/uploads/201309/01/1378037128_5291.jpg")
               .build();
       Call call = mOkHttpClient.newCall(request);
       call.enqueue(new Callback() {
           @Override
           public void onFailure(Call call, IOException e) {
            showlog(e.getMessage());
           }

           @Override
           public void onResponse(Call call, Response response) throws IOException {
               final byte[] data = response.body().bytes();
               runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                       image.setImageBitmap(bmp);
                   }
               });
           }
       });
   }

對於圖片下載,文件下載其實是類似的;圖片下載是通過回調的Response拿到byte[]然後decode成圖片;文件下載則是拿到inputStream做寫文件操作,我們這裡就不贅述了。

3. okHttp網絡請求之封裝

如果每次請求網絡都需要寫重復的代碼絕對是令人頭疼的,網上也有很多對OkHttp封裝的優秀開源項目,譬如OkHttpUtils,封裝的意義就在於更加方便的使用,具有拓展性,但是對OkHttp封裝最需要解決的是以下的兩點:

避免重復代碼調用 將請求結果回調改為UI線程

根據以上兩點,我也做一個簡單的封裝,首先呢我們寫一個抽象類用於請求回調:

public interface ReqCallBack {
    /**響應成功*/
     void onReqSuccess(T result);
    /**響應失敗*/
     void onReqFailed(String errorMsg);
}

接下來創建一個OkHttpManager類封裝OkHttp,並實現了異步GET請求:

  public class OkHttpManager {
        private static volatile OkHttpManager mInstance;//單例引用
        private OkHttpClient mOkHttpClient;//okHttpClient實例
        private Handler okHttpHandler;//全局處理子線程和主線程通信

        /**
         * 初始化OkHttpManager
         */
        public OkHttpManager(Context context) {
            //初始化OkHttpClient
            mOkHttpClient = new OkHttpClient().newBuilder()
                    .connectTimeout(10, TimeUnit.SECONDS)//設置超時時間
                    .readTimeout(10, TimeUnit.SECONDS)//設置讀取超時時間
                    .writeTimeout(10, TimeUnit.SECONDS)//設置寫入超時時間
                    .build();
            //初始化Handler
            okHttpHandler = new Handler(context.getMainLooper());
        }

        /**
         * 獲取單例引用
         */    
        public static OkHttpManager getInstance(Context context) {
            if (mInstance == null) {
                synchronized (OkHttpManager.class) {
                    if (mInstance == null) {
                        mInstance = new OkHttpManager(context);
                    }
                }
            }
            return mInstance;
        }

        /**
         * okHttp get異步請求
         * @param actionUrl 接口地址
         * @param callBack 請求返回數據回調
         * @param  數據泛型
         * @return
         */
        public  Call getAsynHttp(String url, final ReqCallBack callBack) {
            try {
                final Request request = new Request.Builder()
                        .url(url)
                        .build();
                Call call = mOkHttpClient.newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        failedCallBack("訪問失敗", callBack);
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        if (response.isSuccessful()) {
                            String string = response.body().string();
                            successCallBack((T) string, callBack);
                        } else {
                            failedCallBack("服務器錯誤", callBack);
                        }
                    }
                });
                return call;
            } catch (Exception e) {}
            return null;
        }

        /**
         * 統一處理成功信息
         * @param result
         * @param callBack
         * @param 
         */
        private  void successCallBack(final T result, final ReqCallBack callBack) {
            okHttpHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (callBack != null) {
                        callBack.onReqSuccess(result);
                    }
                }
            });
        }

        /**
         * 統一處理失敗信息
         * @param errorMsg
         * @param callBack
         * @param 
         */
        private  void failedCallBack(final String errorMsg, final ReqCallBack callBack) {
            okHttpHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (callBack != null) {
                        callBack.onReqFailed(errorMsg);
                    }
                }
            });
        }       
   }

最後使用這個OkHttpManager來請求網絡:

OkHttpManager.getInstance(this).getAsynHttp("http://www.baidu.com", new ReqCallBack() {
          @Override
          public void onReqSuccess(String result) {
              Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
          }

          @Override
          public void onReqFailed(String errorMsg) {
              showlog(errorMsg);
          }          
       });

是不是很簡單呢?就幾句代碼就實現了GET請求,而且請求結果回調是在UI線程的。這裡只是一個很簡單的封裝例子,如果用在正式項目裡推薦OkHttpUtils。

4. okHttp網絡請求之Json解析

一般情況下服務端默認返回的是Json字符串,上面通過封裝我們直接將Json返回給客戶端。其實封裝內部還能通過GSON解析讓客戶端直接獲取對象。
首先新建兩個Bean文件:

public class Weather {
    public WeatherInfo weatherinfo;
}
public class WeatherInfo {
    public String city;
    public String cityid;
    public String date_y;
    public String temp1;
    public String weather1;

    public String toString() {
        return "[city:"+city+" cityid:"+cityid+" date_y:"+date_y+" temp1:"+temp1+" weather1:"+weather1+"]";
    }
}

改寫上面的OkHttpManager,在服務器端成功返回Json後做一次轉換,將Json字符串轉換成Weather對象:

@Override
public void onResponse(Call call, Response response) throws IOException {
       if (response.isSuccessful()) {
             String string = response.body().string();
             Weather weather = new Gson().fromJson(string, Weather.class);
             successCallBack((T) weather, callBack);
       } else {
             failedCallBack("服務器錯誤", callBack);
       }
}

請求網絡,這裡泛型類型我們傳入Weather:

OkHttpManager.getInstance(this).getAsynHttp("http://weather.51wnl.com/weatherinfo/GetMoreWeather?cityCode=101020100&weatherType=0", new ReqCallBack() {
          @Override
          public void onReqSuccess(Weather weather) {
              WeatherInfo weatherInfo = weather.weatherinfo;
              showlog(weatherInfo.toString());
          }

          @Override
          public void onReqFailed(String errorMsg) {
              showlog(errorMsg);
          }          
       });

這裡寫圖片描述
可以看到,這裡返回的已經是Weather對象了。注意,在正式項目裡對OkHttp做封裝時要考慮全面,對傳進來的不同類型要生成不同的對象,而不僅僅是這裡的Weather。

5. okHttp網絡請求之緩存控制Cache-Control

使用緩存可以讓我們的app不用長時間地顯示令人厭煩的加載圈,提高了用戶體驗,而且還節省了流量,在數據更新不是很頻繁的地方使用緩存就非常有必要了。想要加入緩存不需要我們自己來實現,Okhttp已經內置了緩存,默認是不使用的,如果想使用緩存我們需要手動設置。

服務器支持緩存
如果服務器支持緩存,請求返回的Response會帶有這樣的Header:Cache-Control, max-age=xxx,這種情況下我們只需要手動給okhttp設置緩存就可以讓okhttp自動幫你緩存了。這裡的max-age的值代表了緩存在你本地存放的時間,可以根據實際需要來設置其大小。
首先我們要提供了一個文件路徑用來存放緩存,另外還需要指定緩存的大小就可以創建一個緩存了。

File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(sdcache.getAbsoluteFile(), cacheSize);

創建了這個緩存後我們還需要將其設置到okttpClient對象裡面:

OkHttpClient mOkHttpClient = new OkHttpClient().newBuilder()
              .cache(cache)
              .connectTimeout(20, TimeUnit.SECONDS)
              .readTimeout(20, TimeUnit.SECONDS)
              .build();

服務器不支持緩存
如果服務器不支持緩存就可能沒有指定這個頭部,或者指定的值是如no-store等,但是我們還想在本地使用緩存的話要怎麼辦呢?這種情況下我們就需要使用Interceptor來重寫Respose的頭部信息,從而讓okhttp支持緩存。
如下所示,我們重寫的Response的Cache-Control字段:

public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        return response.newBuilder()
                .removeHeader("Pragma")
                .removeHeader("Cache-Control")
                //cache for 30 days
                .header("Cache-Control", "max-age=" + 3600 * 24 * 30) 
                .build();
    }
}

然後將該Intercepter作為一個NetworkInterceptor加入到okhttpClient中:

OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient mOkHttpClient = okHttpClient.newBuilder()
        .addNetworkInterceptor(new CacheInterceptor())
        .cache(cache)
        .connectTimeout(20, TimeUnit.SECONDS)
        .readTimeout(20, TimeUnit.SECONDS)
        .build();

Request request = new Request.Builder()
                 .url("http://www.baidu.com")
                 .build();
         Call call = mOkHttpClient.newCall(request);
         call.enqueue(new Callback() {
             @Override
             public void onFailure(Call call, IOException e) {}

             @Override
             public void onResponse(Call call, final Response response) throws IOException {
                 if (null != response.cacheResponse()) {
                     String str = response.cacheResponse().toString();
                     showlog("cache--->" + str);
                 } else {
                     response.body().string();
                     String str=response.networkResponse().toString();
                     showlog("network--->" + str);
                 }
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
                         Toast.makeText(getApplicationContext(), "請求成功", Toast.LENGTH_SHORT).show();
                     }
                 });
             }
         });

這樣我們就可以在服務器不支持緩存的情況下使用緩存了。第一次請求會請求網絡得到數據,第二次以及後面的請求則會從緩存中取出數據:
這裡寫圖片描述
當然也有種情況是有的請求每次都需要最新的數據,則在創建Request,來設置cacheControl為“CacheControl.FORCE_NETWORK”,用來表示請求會一直請求網絡得到數據:

final Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .cacheControl(CacheControl.FORCE_NETWORK)
                .build();

這裡寫圖片描述
可以看到每次返回結果都來自網絡。
兩個CacheControl常量介紹:

CacheControl.FORCE_CACHE; //僅僅使用緩存
CacheControl.FORCE_NETWORK;//僅僅使用網絡

但是大家必須注意一點,okhttp的緩存設計和浏覽器的一樣,是用來提升用戶體驗降低服務器負荷的,比如:我們在有網的時候也會先調用緩存,但是有個時間限制,例如1分鐘之內,有網和沒有網都是先讀緩存,這個可以參考下面講解的第一種類型。
如果你想要做成那種離線可以緩存,在線就獲取最新數據的功能,可以參考第二種類型。

第一種類型(有網和沒有網都是先讀緩存)

1、創建攔截器:

Interceptor interceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            String cacheControl = request.cacheControl().toString();
            if (TextUtils.isEmpty(cacheControl)) {
                cacheControl = "public, max-age=60";
            }
            return response.newBuilder()
                    .header("Cache-Control", cacheControl)
                    .removeHeader("Pragma")
                    .build();
        }
    };

設置max-age為60s之後,這60s之內不管你有沒有網,都讀緩存。如果cache沒有過期會直接返回cache而不會發起網絡請求,若過期會自動發起網絡請求。

2、設置client

/**創建OkHttpClient,並添加攔截器和緩存代碼**/
OkHttpClient client = new OkHttpClient.Builder()
          .addNetworkInterceptor(interceptor)
          .cache(cache).build();
第二種類型(離線可以緩存,在線就獲取最新數據)

這種方法和第一種方法的區別是在設置的攔截器上,這裡不能使用NetworkInterceptor,而是需要使用AppInterceptor。
先講一下步驟:
1、首先,給OkHttp設置攔截器
2、然後,在攔截器內做Request攔截操作,在每個請求發出前,判斷一下網絡狀況,如果沒問題繼續訪問,如果有問題,則設置從本地緩存中讀取
3、接下來是設置Response,先判斷網絡,網絡好的時候,移除header後添加cache失效時間為0小時,網絡未連接的情況下設置緩存時間為4周

代碼:
1、給OkHttp設置攔截器(用Interceptor)

OkHttpClient client = new OkHttpClient.Builder()
         .addInterceptor(interceptor)
         .cache(cache).build();

2、Request攔截操作

Request request = chain.request();
/**注意:如果您使用FORCE_CACHE和網絡的響應需求,OkHttp則會返回一個504提示,告訴你不可滿足請求響應。所以我們加一個判斷在沒有網絡的情況下使用*/
if (!isNetworkAvailable(MainActivity.this)) {
            request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE) //無網絡時,強制從緩存取
                        .build();
            showlog("no network");
}

3、設置Response

Response response = chain.proceed(request);
if (isNetworkAvailable(MainActivity.this)) {
           int maxAge = 0 * 60; // 有網絡時,設置緩存超時時間0個小時
           showlog("has network maxAge="+maxAge);
           response.newBuilder()
                   .header("Cache-Control", "public, max-age=" + maxAge)
                   .removeHeader("Pragma")// 清除頭信息,因為服務器如果不支持,會返回一些干擾信息,不清除下面無法生效
                   .build();
} else {
           showlog("network error");
           int maxStale = 60 * 60 * 24 * 28; // 無網絡時,設置超時為4周
           showlog("has maxStale="+maxStale);
           response.newBuilder()
                   .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                   .removeHeader("Pragma")
                   .build();
          showlog("response build maxStale="+maxStale);
 }
 return response;

查看緩存文件:
運行程序,在Android/data/com.hx.okhttp.cache下會發現很多緩存文件,這些緩存文件全是以url的md5加密字段為文件名,每一個response分兩個文件保存,以.0和.1結尾的文件區分。 進去看裡面的內容如下: .0的文件裡面是header,而.1文件裡面是返回的具體內容,即json數據。
這裡寫圖片描述
分別看一下內容吧:
這裡寫圖片描述
因為百度html頁面含有中文,這裡看到數據有亂碼現象
這裡寫圖片描述

6. okHttp取消請求

使用call.cancel()可以立即停止掉一個正在執行的call。如果一個線程正在寫請求或者讀響應,將會引發IOException。當用戶離開一個應用時或者跳到其他界面時,使用Call.cancel()可以節約網絡資源,另外不管同步還是異步的call都可以取消。
也可以通過tags來同時取消多個請求。當你構建一請求時,使用RequestBuilder.tag(tag)來分配一個標簽。之後你就可以用OkHttpClient.cancel(tag)來取消所有帶有這個tag的call。
為了模擬這個場景我們首先創建一個定時的線程池:

private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
private  void cancelCall(){
        OkHttpClient mOkHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .cacheControl(CacheControl.FORCE_NETWORK)
                .build();
        Call call = null;
        call = mOkHttpClient.newCall(request);
        final Call finalCall = call;
        //100毫秒後取消call
        executor.schedule(new Runnable() {
            @Override 
            public void run() {
                finalCall.cancel();
            }
        }, 100, TimeUnit.MILLISECONDS);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {}

            @Override
            public void onResponse(Call call,final Response response) {
                if (null != response.cacheResponse()) {
                    String str = response.cacheResponse().toString();
                    showlog("cache--->" + str);
                } else {
                    try {
                        response.body().string();
                    } catch (IOException e) {
                        showlog("IOException");
                        e.printStackTrace();
                    }
                    String str = response.networkResponse().toString();
                    showlog("network--->" + str);
                }
            }
        });
        showlog("是否取消成功"+call.isCanceled());
    }

100毫秒後調用call.cancel(),為了能讓請求耗時,我們設置每次請求都要請求網絡,運行程序並且不斷的快速點擊發送請求按鈕:
這裡寫圖片描述
很明顯每次cancel()都失敗了,仍舊成功的訪問了網絡。每隔100毫秒來調用call.cancel()顯然時間間隔太長,這段時間網絡已經返回了數據,我們設置為1毫秒並不斷的快速的點擊發送請求按鈕:
這裡寫圖片描述
這次每次cancel()操作都成功了。

OkHttpUtils封裝類

這裡寫圖片描述

1.支持的常用功能

一般的 get,post,put,delete,head,options請求 基於Post的大文本數據上傳,postString(),postJson()等 多文件和多參數統一的表單上傳(允許監聽上傳進度) 支持一個key上傳一個文件,也可以一個Key上傳多個文件 大文件下載和下載進度回調 大文件上傳和上傳進度回調 支持cookie的內存存儲和持久化存儲,支持傳遞自定義cookie 提供網絡緩存功能,默認支持304緩存協議,並額外擴展了三種本地緩存模式 支持301、302重定向 支持鏈式調用 支持可信證書和自簽名證書的https訪問 支持根據Tag取消網絡請求 支持自定義泛型Callback,自動根據泛型返回對象

2.支持的擴展功能

統一的文件下載管理(DownloadManager)
默認使用的是 get 請求,同時下載數量為3個,支持斷點下載,斷點信息使用ORMLite數據庫框架保存,默認下載路徑/storage/emulated/0/download,下載路徑和下載數量都可以在代碼中配置,下載管理使用了服務提高線程優先級,避免後台下載時被系統回收。
當你的項目需要做大量的下載的時候,並且多個頁面需要監聽下載進度,使用該擴展讓你更方便。原生支持下載任務的開始、暫停、停止、出錯、完成五個狀態,當同時下載任務數量超過3個(可代碼動態設置)時,後續任務自動等待,當有任務下載完成時,等待任務按照優先級自動開始下載。

統一的文件上傳管理(UploadManager)
默認使用的是 post 上傳請求,該上傳管理為簡單管理,不支持斷點續傳和分片上傳,只是簡單的將所有上傳任務使用線程池進行了統一管理,默認同時上傳數量為1個。由於斷點分片上傳的技術需要大量的服務端代碼配合,同時也會極大的增加客戶端代碼量,所以綜合考慮,該框架不做實現。如果確實有特殊需要,可以自己做擴展。

3.OkHttpUtils的優勢

優勢一:性能高,專注於簡單易用的網絡請求,使用主流的okhttp進行封裝,對於okhttp大家都知道,在Android4.4的源碼中可以看到HttpURLConnection已經替換成OkHttp實現了,並且支持HTTP2/SPDY黑科技,支持socket自動選擇最好路線,並支持自動重連,擁有自動維護的socket連接池,減少握手次數,擁有隊列線程池,輕松寫並發。
優勢二:特有的網絡緩存模式,是大多數網絡框架所不具備的,說一個應用場景,老板說我們的app不僅需要在有網的情況下展示最新的網絡數據,還要在沒網的情況下使用緩存數據,這時候是不是項目中出現了大量的代碼判斷當前網絡狀況,根據不同的狀態保存不同的數據,然後決定是否使用緩存。細想一下,這是個通用的寫法,於是OkHttpUtils提供了四種緩存模式,讓你不用關心緩存的實現,而專注於數據的處理。
優勢三:方便易用的擴展接口,可以添加全局的公共參數,全局攔截器,全局超時時間,更可以對單個請求定制攔截器,超時時間,請求參數修改等等,在使用上更是方便,原生支持的鏈式調用讓你的請求更加清晰。
優勢四:強大的Cookie保持策略,我們知道在客戶端對cookie的獲取是個不太簡單的事情,特別是還要處理cookie的過期時間,持久化策略等等,OkHttpUtils幫你徹底解決Cookie的難題,默認擁有內存存儲和持久化存儲兩種實現,cookie全程自動管理,並且提供了額外的addCookie方式,允許介入到自動管理的過程中,添加你想創建的任何cookie。

4.使用方法

Eclipse的用戶,導入JAR包或添加依賴工程:
見我後面的Demo,用得是依賴工程。

添加網絡訪問權限和讀寫SD卡權限:



5.使用注意事項

okhttputils使用的okhttp的版本是最新的 3.2.0 版本,和以前的 2.x 的版本可能會存在沖突。 okhttpserver是對okhttputils的擴展,統一了下載管理和上傳管理,對項目有需要做統一下載的可以考慮使用該擴展,不需要的可以直接使用okhttputils即可。 對於緩存模式使用,需要與返回對象相關的所有javaBean必須實現Serializable接口,否者會報NotSerializableException。 使用緩存時,如果不指定cacheKey,默認是用url帶參數的全路徑名為cacheKey。 使用該網絡框架時,必須要在 Application 中做初始化 OkHttpUtils.init(this);。

6.全局配置

一般在 Aplication,或者基類中,只需要調用一次即可,可以配置調試開關,全局的超時時間,公共的請求頭和請求參數等信息,所有的請求參數都支持中文。

    @Override
    public void onCreate() {
        super.onCreate();

        //---------這裡給出的是示例代碼,告訴你可以這麼傳,實際使用的時候,根據需要傳,不需要就不傳-------------//
        HttpHeaders headers = new HttpHeaders();
        headers.put("commonHeaderKey1", "commonHeaderValue1");    //header不支持中文
        headers.put("commonHeaderKey2", "commonHeaderValue2");
        HttpParams params = new HttpParams();
        params.put("commonParamsKey1", "commonParamsValue1");     //param支持中文,直接傳,不要自己編碼
        params.put("commonParamsKey2", "這裡支持中文參數");
        //-----------------------------------------------------------------------------------//

        //必須調用初始化
        OkHttpUtils.init(this);

        //以下設置的所有參數是全局參數,同樣的參數可以在請求的時候再設置一遍,那麼對於該請求來講,請求中的參數會覆蓋全局參數
        //好處是全局參數統一,特定請求可以特別定制參數
        try {
            //以下都不是必須的,根據需要自行選擇,一般來說只需要 debug,緩存相關,cookie相關的 就可以了
            OkHttpUtils.getInstance()
                    //打開該調試開關,控制台會使用 紅色error 級別打印log,並不是錯誤,是為了顯眼,不需要就不要加入該行
                    .debug("OkHttpUtils")
                    //如果使用默認的 60秒,以下三行也不需要傳
                    .setConnectTimeout(OkHttpUtils.DEFAULT_MILLISECONDS)  //全局的連接超時時間
                    .setReadTimeOut(OkHttpUtils.DEFAULT_MILLISECONDS)     //全局的讀取超時時間
                    .setWriteTimeOut(OkHttpUtils.DEFAULT_MILLISECONDS)    //全局的寫入超時時間
                    //可以全局統一設置緩存模式,默認是不使用緩存,可以不傳
                    .setCacheMode(CacheMode.NO_CACHE)
                    //可以全局統一設置緩存時間,默認永不過期
                    .setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)
                    //如果不想讓框架管理cookie,以下不需要
//                  .setCookieStore(new MemoryCookieStore()) //cookie使用內存緩存(app退出後,cookie消失)
                    .setCookieStore(new PersistentCookieStore()) //cookie持久化存儲,如果cookie不過期,則一直有效

                    //可以設置https的證書,以下幾種方案根據需要自己設置
//                    .setCertificates()                                  //方法一:信任所有證書(選一種即可)
//                    .setCertificates(getAssets().open("srca.cer"))      //方法二:也可以自己設置https證書(選一種即可)
//                    .setCertificates(getAssets().open("aaaa.bks"), "123456", getAssets().open("srca.cer"))//方法三:傳入bks證書,密碼,和cer證書,支持雙向加密

                    //可以添加全局攔截器,不會用的千萬不要傳,錯誤寫法直接導致任何回調不執行
//                .addInterceptor(new Interceptor() {
//                    @Override
//                    public Response intercept(Chain chain) throws IOException {
//                        return chain.proceed(chain.request());
//                    }
//                })

                    //這兩行同上,不需要就不要傳
                    .addCommonHeaders(headers)                                         //設置全局公共頭
                    .addCommonParams(params);                                          //設置全局公共參數
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved