1. 程式人生 > >Android RxVolley = Volley + RxJava + OkHttp

Android RxVolley = Volley + RxJava + OkHttp

ext vol pst 之前 timeout subscribe == thread 復用

  • Github:https://github.com/kymjs/RxVolley
  • RxVolley使用文檔 V1.0:http://rxvolley.mydoc.io/

一.RxVolley使用指南

1.概述

RxVolley是一個基於Volley的網絡請求庫;同時支持RxJava;可以選擇使用OKHttp替代默認的 HttpUrlConnection 做網絡請求;可以選擇使用圖片加載功能(復用的網絡請求將有效減少apk體積);移除了原Volley的 HttpClient 相關 API ,可在 API23 環境編譯;內置了RxBus的實現,可有效替換掉EventBus等相關庫;

2.依賴

使用RxVolley,需要在你的build.gradle文件中加入
compile com.kymjs.rxvolley:rxvolley:1.0.7
如果你還想使用OKhttp來替代默認的HttpUrlconnection,需要加入
compile com.kymjs.rxvolley:okhttp:1.0.7
如果你想使用RxVolley的圖片加載功能(復用http模塊可以有效減少apk大小),需要加入
compile com.kymjs.rxvolley:bitmapcore:1.0.7

使用 RxVolley 做網絡請求

3.簡單實現

//get請求簡潔版實現
RxVolley.get("http://www.kymjs.com/feed.xml", new HttpCallback() {
    @Override
    public void onSuccess(String t) {
        Loger.debug("請求到的數據:" + t);
    }
});

//post請求簡潔版實現
HttpParams params = new HttpParams();
params.put("name", "kymjs");
params.put("age", 18);
params.put("image", new File("path"))//文件上傳 RxVolley.post("http://kymjs.com/feed.xml", params, new HttpCallback() { @Override public void onSuccess(String t) { Loger.debug("請求到的數據:" + t); } });

4.對Cookie等請求頭的處理

//用戶登錄邏輯(HttpCallback中有很多重載方法,可以選擇需要的實現)
HttpParams params = new HttpParams();
params.put("name", "kymjs");
params.put("age", 18);
params.put("password", "helloword");
RxVolley.post("http://kymjs.com/login", params, new HttpCallback() {
    @Override
    public void onSuccess(Map<String, String> headers, byte[] t) {
        Loger.debug("請求到的數據:" + new String(t));
        // 獲取到的cookie
        Loger.debug("===" + headers.get("Set-Cookie"));
    }
});
//向服務器傳遞cookie信息
HttpParams params = new HttpParams();
params.put("name", "kymjs");
params.put("age", 100);

params.putHeaders("cookie", "your cookie");

RxVolley.post("http://kymjs.com/update", params, new HttpCallback() {
    @Override
    public void onSuccess(String t) {
        Loger.debug("請求到的數據:" + t);
    }
});

比起 入門 章節講述的網絡請求,你可能希望有更多的需求

5.構建網絡請求

HttpParams params = new HttpParams();

//同之前的設計,傳遞 http 請求頭可以使用 putHeaders()
params.putHeaders("cookie", "your cookie");
params.putHeaders("User-Agent", "rxvolley"); 

//傳遞 http 請求參數可以使用 put()
params.put("name", "kymjs");
params.put("age", "18");

//http請求的回調,內置了很多方法,詳細請查看源碼
//包括在異步響應的onSuccessInAsync():註不能做UI操作
//網絡請求成功時的回調onSuccess()
//網絡請求失敗時的回調onFailure():例如無網絡,服務器異常等
HttpCallback callback = new HttpCallback(){
    @Override
    public void onSuccessInAsync(byte[] t) {
    }
    @Override
    public void onSuccess(String t) {
    }
    @Override
    public void onFailure(int errorNo, String strMsg) {
    }
}

ProgressListener listener = new ProgressListener(){
    /**
     * @param transferredBytes 進度
     * @param totalSize 總量
     */
    @Override
    public void onProgress(long transferredBytes, long totalSize){
    }
}

new RxVolley.Builder()
    .url("http://www.kymjs.com/rss.xml") //接口地址  
    //請求類型,如果不加,默認為 GET 可選項: 
    //POST/PUT/DELETE/HEAD/OPTIONS/TRACE/PATCH  
    .httpMethod(RxVolley.Method.GET) 
    //設置緩存時間: 默認是 get 請求 5 分鐘, post 請求不緩存  
    .cacheTime(6) 
    //內容參數傳遞形式,如果不加,默認為 FORM 表單提交,可選項 JSON 內容
    .contentType(RxVolley.ContentType.FORM)
    .params(params) //上文創建的HttpParams請求參數集
    //是否緩存,默認是 get 請求 5 緩存分鐘, post 請求不緩存
    .shouldCache(true) 
    .progressListener(listener) //上傳進度
    .callback(callback) //響應回調
    .encoding("UTF-8") //編碼格式,默認為utf-8
    .doTask();  //執行請求操作

6.對 RxJava 的支持

RxVolley 支持返回一個 Observable 類型的數據,如下是 Result 類的原型
public class Result {
    public Map<String, String> header;
    public byte[] data;

    public Result(Map<String, String> header, byte[] data) {
        this.header = header;
        this.data = data;
    }
}

執行一次請求,並返回 Observable

Observable<Result> observable = new RxVolley.Builder()
    .url("http://www.kymjs.com/rss.xml")
    //default GET or POST/PUT/DELETE/HEAD/OPTIONS/TRACE/PATCH
    .httpMethod(RxVolley.Method.POST) 
    .cacheTime(6) //default: get 5min, post 0min
    .params(params)
    .contentType(RxVolley.ContentType.JSON)
    .getResult();  // 使用getResult()來返回RxJava數據類型

//當拿到 observable 對象後,你可以設置你自己的 subscriber 
observable.subscribe(subscriber);
完整的使用示例
public class MainActivity extends AppCompatActivity {

    private Subscription subscription;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable<Result> observable = new RxVolley.Builder()
                .url("http://kymjs.com/feed.xml")
                .contentType(RxVolley.ContentType.FORM)
                .getResult();

        subscription = observable
                .map(new Func1<Result, String>() {
                    @Override
                    public String call(Result result) {
                        return new String(result.data);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String result) {
                        Log.i("kymjs", "======網絡請求" + result);
                    }
                });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (subscription != null && subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }
    }
}

7.自定義請求

也許你是 Volley 的重度使用者(就像我),那麽你一定是因為 Volley 自由的擴展性而愛上它的。 
你可以通過創建一個Request
RxVolley.Builder().setRequest(yourRequest).doTask();
去執行你的自定義 Request

一個典型自定義Request的示例:
/**
 * Form表單形式的Http請求
 */
public class FormRequest extends Request<byte[]> {

    private final HttpParams mParams;

    public FormRequest(RequestConfig config, HttpParams params, HttpCallback callback) {
        super(config, callback);
        if (params == null) {
            params = new HttpParams();
        }
        this.mParams = params;
    }

    @Override
    public String getCacheKey() {
        if (getMethod() == RxVolley.Method.POST) {
            return getUrl() + mParams.getUrlParams();
        } else {
            return getUrl();
        }
    }

    @Override
    public String getBodyContentType() {
        if (mParams.getContentType() != null) {
            return mParams.getContentType();
        } else {
            return super.getBodyContentType();
        }
    }

    @Override
    public ArrayList<HttpParamsEntry> getHeaders() {
        return mParams.getHeaders();
    }

    @Override
    public byte[] getBody() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            mParams.writeTo(bos);
        } catch (IOException e) {
            Loger.debug("FormRequest#getBody()--->IOException writing to ByteArrayOutputStream");
        }
        return bos.toByteArray();
    }

    @Override
    public Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, response.headers,
                HttpHeaderParser.parseCacheHeaders(getUseServerControl(), getCacheTime(),
                        response));
    }

    @Override
    protected void deliverResponse(ArrayList<HttpParamsEntry> headers, final byte[] response) {
        if (mCallback != null) {
            HashMap<String, String> map = new HashMap<>(headers.size());
            for (HttpParamsEntry entry : headers) {
                map.put(entry.k, entry.v);
            }
            mCallback.onSuccess(map, response);
        }
    }

    @Override
    public Priority getPriority() {
        return Priority.IMMEDIATE;
    }
}

8.文件(圖片)下載

利用 RxVolley 的自定義請求,在庫中內置了文件下載功能。你可以使用
//下載進度(可選參數,不需要可不傳)
listener = new ProgressListener() {
    @Override
    public void onProgress(long transferredBytes, long totalSize) {
        Loger.debug(transferredBytes + "======" + totalSize);
    }
}

//下載回調,內置了很多方法,詳細請查看源碼
//包括在異步響應的onSuccessInAsync():註不能做UI操作
//下載成功時的回調onSuccess()
//下載失敗時的回調onFailure():例如無網絡,服務器異常等
HttpCallback callback = new HttpCallback(){
    @Override
    public void onSuccessInAsync(byte[] t) {
    }
    @Override
    public void onSuccess(String t) {
    }
    @Override
    public void onFailure(int errorNo, String strMsg) {
    }
}

RxVolley.download(FileUtils.getSDCardPath() + "/a.apk",
    "https://www.oschina.net/uploads/osc-android-app-2.4.apk",
    listener, callback);

download()原型
既然說了下載功能是利用 RxVolley 的自定義請求創建的,不妨看看他的方法實現:

  /**
     * 下載
     *
     * @param storeFilePath    本地存儲絕對路徑
     * @param url              要下載的文件的url
     * @param progressListener 下載進度回調
     * @param callback         回調
     */
    public static void download(String storeFilePath, String url, ProgressListener
            progressListener, HttpCallback callback) {
        RequestConfig config = new RequestConfig();
        config.mUrl = url;
        FileRequest request = new FileRequest(storeFilePath, config, callback);
        request.setOnProgressListener(progressListener);
        new Builder().setRequest(request).doTask();
    }

9.更多可選設置

理論上來說,一切的請求設置都可以通過自定義 Request 來完成。 
但是,如果你和我一樣是個懶人,當然更希望這些早就有人已經做好了。
  • 設置文件緩存的路徑
默認的文件緩存路徑是在SD卡根目錄的 /RxVolley 文件夾下,你可以通過如下語句設置你的 cacheFolder
RxVolley.setRequestQueue(RequestQueue.newRequestQueue(cacheFolder));

需要註意的是,setRequestQueue 方法必須在 RxVolley.Build() 方法執行之前調用,也就是在使用 RxVolley 以前先設置配置信息。建議在 Application 類中完成這些設置。

  • Https設置
如果不設置,默認信任全部的https證書。可以傳入自定義 SSLSocketFactory
RxVolley.setRequestQueue(RequestQueue.newRequestQueue(cacheFolder), new HttpConnectStack(null, sslSocketFactory));
需要註意的是,setRequestQueue 方法必須在 RxVolley.Build() 方法執行之前調用,也就是在使用 RxVolley 以前先設置配置信息。建議在 Application 類中完成這些設置。

一個自定義設置SSLSocketFactory的相關示例:
//下載的證書放到項目中的assets目錄中
InputStream ins = context.getAssets().open("app_pay.cer"); 
CertificateFactory cerFactory = CertificateFactory
        .getInstance("X.509");
Certificate cer = cerFactory.generateCertificate(ins);
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", cer);

SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);

RxVolley.setRequestQueue(RequestQueue.newRequestQueue(RxVolley.CACHE_FOLDER), new HttpConnectStack(null, sslSocketFactory));
Build()中的可選設置
詳細請參閱 RxVolley$Builder 類中代碼。
//請求超時時間   
timeout()    

//為了更真實的模擬網絡,如果讀取緩存,延遲一段時間再返回緩存內容   
delayTime()   

//緩存有效時間,單位分鐘  
cacheTime()  

//使用服務器控制的緩存有效期,即cookie有效期  
//(如果使用服務器端控制,則無視#cacheTime())  
useServerControl()   

//啟用緩存  
shouldCache()  

//重連策略,Volley默認的重連策略是timeout=3000,重試1次  
retryPolicy()

二.Cookie持久化封裝

RxVolley 默認對於 cookie 的操作是會從 HttpCallback 中返回 cookie,需要手動保存到本地。 
如果你希望框架能夠自動存儲 cookie,可以這麽做:

按需要選擇繼承FormRequest或者JsonRequest (直接繼承 Request 類也可以,但是復雜) 並重寫
@Override
protected void deliverResponse(ArrayList<HttpParamsEntry> headers, final byte[] response) {
    if (mCallback != null) {
        HashMap<String, String> map = new HashMap<>(headers.size());
        for (HttpParamsEntry entry : headers) {
            map.put(entry.k, entry.v);
        }
        mCallback.onSuccess(map, response);
    } 
}
邏輯如上述代碼,其中的map即包含了服務器返回的cookie,可以做你自己的操作了。 
最終執行你的自定義 Request
new RxVolley.Builder().setRequest(xxxxx).doTask();

在傳遞 Cookie 作為請求頭的時候,建議寫一個工具類,例如

public static HttpParams getHttpParams() {
    HttpParams params = new HttpParams();
    params.putHeader("cookie");
    return params;
}

三.使用 OkHttp

使用 OkHttp 替代HttpUrlconnection

Volley 允許你創建自己的網絡請求執行器,執行器需要實現IHttpStack接口

RxVolley 的 okhttp module 已經有了使用 OkHttp 作為請求執行器的實現。

你可以使用如下代碼設置,依舊需要註意的是,setRequestQueue 方法必須在 RxVolley.Build() 方法執行之前調用,也就是在使用 RxVolley 以前先設置配置信息。建議在 Application 類中完成這些設置。
RxVolley.setRequestQueue(RequestQueue.newRequestQueue(RxVolley.CACHE_FOLDER, new OkHttpStack(new OkHttpClient())));
使用 OkHttp 相關功能需要在你的 build.gradle 文件中加入
compile com.kymjs.rxvolley:okhttp:1.0.5

四.Issue反饋

  • https://github.com/kymjs/RxVolley/issues

Android RxVolley = Volley + RxJava + OkHttp