XDroidRequest 是一款網絡請求框架,它的功能也許會適合你。這是本項目的第三版了,前兩版因爲擴展性問題一直不滿意,思考來 思考去仍是以爲Google的Volley的擴展性最強,因而借鑑了Volley的責任鏈模式,因此有了這個第三版.php
1 適配 Android 6.0 ,再也不使用HttpClient相關API 2 一行代碼發送請求,提供多種回調函數供選擇, 3 支持8種網絡請求方式 GET,POST,PUT,DELETE,HEAD,OPTIONS,TRACE,PATCH 4 支持請求的優先級設置,優先級高的將先於優先級低的發送請求 5 支持取消請求,能夠取消當前已發送的請求(可自定義取消請求的依據條件),也能夠取消請求隊列中還未發送的請求 6 支持多請求併發,多個請求同時發送,底層使用固定數量線程池,可設置線程池的大小 7 支持重複請求的判斷,當有重複的請求將掛起,等待第一個請求完成後,掛起的請求使用已經請求完畢的緩存,若是未開啓緩存,則會繼續請求網絡 8 支持請求失敗重試,默認重試2次,重試超時時間會遞增,遞增速率可設置,默認爲1倍遞增 9 支持多文件與大文件上傳,能夠與參數一塊兒發送至服務器,提供上傳進度回調 10 支持大文件下載,提供下載進度回調 11 支持發送JSON數據 12 自動網絡斷定,可設置此時是否顯示緩存數據 13 請求結果自動解析,可泛型任何JAVA BEAN,默認實現了GSON解析,可自定義 14 多種錯誤類型斷定 15 擴展性強,可自定義發送請求方式與解析請求結果 16 支持強大的緩存控制 17 支持緩存配置,可配置磁盤緩存路徑,磁盤緩存最大值,磁盤緩存當前佔有大小,磁盤緩存清理 內存緩存最大值大小,內存緩存清理 18 支持緩存管理與控制,包括本地請求緩存一系列信息查詢以及對緩存的手動操做
1 XDroidRequest使用了二級緩存,內存緩存與磁盤緩存,內存緩存使用LruCache,磁盤緩存使用DiskLruCache 2 setShouldCache(true) ,一個開關控制是否使用緩存的功能 3 setUseCacheDataAnyway(false), 是否老是使用緩存,這個開關開啓後,將每次首先從內存和本地查找緩存,有的話直接使用緩存, 請求會在後臺執行,完成後會更新緩存。若是沒有緩存將直接進行網絡請求獲取,完成後會更新緩存. 4 setUseCacheDataWhenRequestFailed(true) ,是否在請求失敗後使用緩存數據,無網絡屬於請求失敗,能夠保證即便沒有網絡,或者 請求也有數據展現. 5 setUseCacheDataWhenTimeout(true) ,是否在請求超時後直接使用緩存,這裏的超時時間並非網絡請求的超時時間,而是咱們 設定一個時間,超過這個時間後,無論請求有沒有完成都直接使用緩存,後臺的請求完成後會自動更新緩存 6 setUseCacheDataWhenUnexpired(true),是否使用緩存當緩存未過時的時候,這個開關也是常常開啓的開關,每一個緩存都會對應一個過時 時間,先從內存查找緩存,沒有的話再從磁盤查找,有緩存且過時的話,將直接使用緩存數據,當過時以後會進行網絡請求,請求完成後會更新 內存緩存與磁盤。沒有緩存將直接進行網絡請求,請求完成後會更新內存與磁盤緩存 7 setRetryWhenRequestFailed(true) ,是否進行重試,當請求失敗的時候,默認開啓,重試2次,不須要重試功能的話可關閉 8 setNeverExpired(false); 設置緩存是否永不過時
Download demo.apkjava
1.初始化,應用啓動的時候進行,主要初始化緩存的路徑等信息數據庫
XRequest.initXRequest(getApplicationContext());
2.發起請求api
① GET請求緩存
/**
* 簡單的Get請求
* @param mRequestTag 請求的tag,可根據此tag取消請求
* @param url 請求地址
* @param OnRequestListener 請求結果回調
*/
XRequest.getInstance().sendGet(mRequestTag, url, new OnRequestListenerAdapter<String>() {
@Override
public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
super.onDone(request, headers, result, dataType);
}
});
② POST請求服務器
String url = "http://apis.baidu.com/heweather/weather/free";
RequestParams params = new RequestParams();
params.putHeaders("apikey", "能夠到apistore申請");
params.putParams("city", "hefei");
XRequest.getInstance().sendPost(mRequestTag, url, params, new OnRequestListenerAdapter<String>() {
@Override
public void onRequestFailed(Request<?> request, HttpException httpException) {
super.onRequestFailed(request, httpException);
switch (httpException.getHttpErrorCode()) {
case HttpError.ERROR_NOT_NETWORK:
Toast.makeText(context, "網絡未鏈接,請檢查", Toast.LENGTH_SHORT).show();
break;
}
}
@Override
public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
Toast.makeText(context, "獲取信息失敗,系統已經爲您重試" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
CLog.i("POST請求結果失敗,正在重試,當前重試次數:" + currentRetryCount);
}
@Override
public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
@Override
public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
File currentFile) {
CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
@Override
public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
super.onDone(request, headers, result, dataType);
}
});
③ 發送JSON字符串參數網絡
RequestParams params = new RequestParams();
params.putParams(
"{\"uid\":863548,\"stickys\":[{\"id\":29058,\"iid\":0,\"content\":\"內容\",\"color\":\"green\",\"createtime\":\"2015-04-16 16:26:17\",\"updatetime\":\"2015-04-16 16:26:17\"}]}");
XRequest.getInstance().sendPost(mRequestTag, url, params, new OnRequestListenerAdapter<String>() {
@Override
public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
super.onDone(request, headers, result, dataType);
}
});
④上傳文件併發
String url = "http://192.168.1.150/upload_multi.php";
RequestParams params = new RequestParams();
params.put("file[0]", new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "app-debug.apk"));
params.put("file[1]", new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "photoview.apk"));
params.putParams("file_name", "上傳的文件名稱");
XRequest.getInstance().upload(mRequestTag, url, params, new OnRequestListenerAdapter<String>() {
@Override
public void onRequestPrepare(Request<?> request) {
Toast.makeText(context, "請求準備", Toast.LENGTH_SHORT).show();
CLog.i("請求準備");
}
@Override
public void onRequestFailed(Request<?> request,HttpException httpException) {
Toast.makeText(context, "請求結果失敗", Toast.LENGTH_SHORT).show();
CLog.i("請求結果失敗");
}
@Override
public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
Toast.makeText(context, "獲取信息失敗,系統已經爲您重試" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
CLog.i("請求結果失敗,正在重試,當前重試次數:" + currentRetryCount);
}
@Override
public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
File currentFile) {
CLog.i("正在上傳第%s個文件,當前進度:%d , 總大小 : %d" ,currentFileIndex,transferredBytesSize,totalSize);
mUploadProgressBar.setMax((int) totalSize);
mUploadProgressBar.setProgress((int) transferredBytesSize);
}
@Override
public void onDone(Request<?> request, Map<String, String> headers, String response, DataType dataType) {
Toast.makeText(context, "請求完成", Toast.LENGTH_SHORT).show();
}
});
測試了上傳百兆以上文件無壓力,若是你想測試多文件上傳,下面的PHP多文件上傳代碼供參考。要注意的是PHP默認上傳2M之內文件,須要本身改下 配置文件,網上不少,搜索便可app
<?php
foreach($_FILES['file']['error'] as $k=>$v)
{
$uploadfile = './upload/'. basename($_FILES['file']['name'][$k]);
if (move_uploaded_file($_FILES['file']['tmp_name'][$k], $uploadfile))
{
echo "File : ", $_FILES['file']['name'][$k] ," is valid, and was successfully uploaded.\n";
}
else
{
echo "Possible file : ", $_FILES['file']['name'][$k], " upload attack!\n";
}
}
echo "成功接收附加字段:". $_POST['file_name'];
?>
⑤下載文件框架
String url = "http://192.168.1.150/upload/xiaokaxiu.apk";
String downloadPath = "/sdcard/xrequest/download";
String fileName = "test.apk";
XRequest.getInstance().download(mRequestTag, url, downloadPath,fileName, new OnRequestListenerAdapter<File>() {
@Override
public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
CLog.i("正在下載, 當前進度:%d , 總大小 : %d" ,transferredBytesSize,totalSize);
mDownloadProgressBar.setMax((int) totalSize);
mDownloadProgressBar.setProgress((int) transferredBytesSize);
}
@Override
public void onDone(Request<?> request, Map<String, String> headers, File result, DataType dataType) {
CLog.i("下載完成 : %s",result != null?result.toString():"獲取File爲空");
}
});
⑥關於回調
請求回調OnRequestListener,回調函數不少,根據本身需求選擇性複寫便可,傳入OnRequestListener默認實現類OnRequestListenerAdapter便可
XRequest.getInstance().sendGet(mRequestTag, url, cacheKey, params, new OnRequestListener<String>() {
/**
* 請求前準備回調
* 運行線程:主線程
* @param request 當前請求對象
*/
@Override
public void onRequestPrepare(Request<?> request) {
Toast.makeText(context, "GET請求準備", Toast.LENGTH_SHORT).show();
CLog.i("GET請求準備");
}
/**
* 請求完成回調
* 運行線程:主線程
* @param request 當前請求對象
* @param headers 請求結果頭文件Map集合
* @param result 請求結果泛型對象
*/
@Override
public void onRequestFinish(Request<?> request, Map<String, String> headers, String result) {
Toast.makeText(context, "GET請求結果獲取成功", Toast.LENGTH_SHORT).show();
CLog.i("GET請求結果獲取成功");
}
/**
* 請求失敗回調
* 運行線程:主線程
* @param request 當前請求對象
* @param httpException 錯誤類對象,包含錯誤碼與錯誤描述
*/
@Override
public void onRequestFailed(Request<?> request, HttpException httpException) {
Toast.makeText(context, "GET請求結果失敗", Toast.LENGTH_SHORT).show();
CLog.i("GET請求結果失敗");
}
/**
* 請求失敗重試回調
* 運行線程:主線程
* @param request 當前請求對象
* @param currentRetryCount 當前重試次數
* @param previousError 上一個錯誤類對象,包含錯誤碼與錯誤描述
*/
@Override
public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
Toast.makeText(context, "獲取信息失敗,系統已經爲您重試" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
CLog.i("GET請求結果失敗,正在重試,當前重試次數:" + currentRetryCount);
}
/**
* 下載進度回調
* 運行線程:子線程
* @param request 當前請求對象
* @param transferredBytesSize 當前下載大小
* @param totalSize 總大小
*
*/
@Override
public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
/**
* 上傳進度回調
* 運行線程:子線程
* @param request 當前請求對象
* @param transferredBytesSize 當前寫入進度
* @param totalSize 總進度
* @param currentFileIndex 當前正在上傳的是第幾個文件
* @param currentFile 當前正在上傳的文件對象
*
*/
@Override
public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
File currentFile) {
CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
/**
* 緩存數據加載完成回調
* 運行線程:主線程
* @param request 當前請求對象
* @param headers 緩存的頭信息Map集合
* @param result 緩存的數據結果對象
*/
@Override
public void onCacheDataLoadFinish(Request<?> request, Map<String, String> headers, String result) {
Toast.makeText(context, "GET請求緩存加載成功", Toast.LENGTH_SHORT).show();
CLog.i("GET請求緩存加載成功");
}
/**
* 解析網絡數據回調,請求完成後,若是須要作耗時操做(好比寫入數據庫)可在此回調中進行,不會阻塞UI
* 運行線程:子線程
* @param request 當前請求對象
* @param networkResponse 網絡請求結果對象,包含byte數據流與頭信息等
* @param result 解析byte數據流構建的對象
*/
@Override
public void onParseNetworkResponse(Request<?> request, NetworkResponse networkResponse, String result) {
CLog.i("GET請求網絡數據解析完成");
}
/**
* 此請求最終完成回調,每次請求只會調用一次,不管此請求走的緩存數據仍是網絡數據,最後交付的結果走此回調
* 運行線程:主線程
* @param request 當前請求對象
* @param headers 最終交付數據的頭信息
* @param result 最終交付的請求結果對象
* @param dataType 最終交付的數據類型枚舉,網絡數據/緩存數據
*/
@Override
public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
Toast.makeText(context, "GET請求完成", Toast.LENGTH_SHORT).show();
}
});
下面是選擇性複寫回調函數
String url = "http://apis.baidu.com/heweather/weather/free";
RequestParams params = new RequestParams();
params.putHeaders("apikey", "能夠到apistore申請");
params.putParams("city", "hefei");
String cacheKey = url + "post"; //與GET請求的URL同樣,爲了不一樣的緩存key、這裏從新指定緩存key
XRequest.getInstance().sendPost(mRequestTag, url, cacheKey, params, new OnRequestListenerAdapter<String>() {
@Override
public void onRequestFailed(Request<?> request, HttpException httpException) {
super.onRequestFailed(request, httpException);
switch (httpException.getHttpErrorCode()) {
case HttpError.ERROR_NOT_NETWORK:
Toast.makeText(context, "網絡未鏈接,請檢查", Toast.LENGTH_SHORT).show();
break;
}
}
@Override
public void onRequestRetry(Request<?> request, int currentRetryCount, HttpException previousError) {
Toast.makeText(context, "獲取信息失敗,系統已經爲您重試" + currentRetryCount+"次", Toast.LENGTH_SHORT).show();
CLog.i("POST請求結果失敗,正在重試,當前重試次數:" + currentRetryCount);
}
@Override
public void onRequestDownloadProgress(Request<?> request, long transferredBytesSize, long totalSize) {
CLog.i("onRequestDownloadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
@Override
public void onRequestUploadProgress(Request<?> request, long transferredBytesSize, long totalSize, int currentFileIndex,
File currentFile) {
CLog.i("onRequestUploadProgress current:%d , total : %d" ,transferredBytesSize,totalSize);
}
@Override
public void onDone(Request<?> request, Map<String, String> headers, String result, DataType dataType) {
super.onDone(request, headers, result, dataType);
}
});
}
⑦自動解析
String url = "http://apis.baidu.com/apistore/aqiservice/citylist";
RequestParams params = new RequestParams();
params.putHeaders("apikey", "能夠到apistore申請");
XRequest.getInstance().sendPost(mRequestTag, url, params, CityRootBean.class, new OnRequestListenerAdapter<CityRootBean<CityBean>>() {
@Override
public void onDone(Request<?> request, Map<String, String> headers, CityRootBean<CityBean> result,
DataType dataType) {
CLog.i("Bean信息:" + (result == null ? "null" : result.toString()));
}
});
⑧緩存配置
(1)初始化的時候若是想要指定緩存路徑,大小等信息,可參照以下代碼
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
configXReqeustCache();
}
@SuppressLint("SdCardPath")
private void configXReqeustCache() {
//磁盤緩存路徑
File DISK_CACHE_DIR_PATH = new File("/sdcard/xrequest/diskcache");
//磁盤緩存最大值
int DISK_CACHE_MAX_SIZE = 30*1024*1024;
//XRequest.initXRequest(getApplicationContext());
XRequest.initXRequest(getApplicationContext(), DISK_CACHE_MAX_SIZE, DISK_CACHE_DIR_PATH);
}
}
(2)查找當前緩存數據佔用的空間
long diskCacheCurrentSize = RequestCacheManager.getInstance().getAllDiskCacheSize();
(3)查找緩存路徑
String diskCacheDir = RequestCacheManager.getInstance().getDiskCacheDirectory().getPath();
(4)查詢當前緩存最大值
long diskCacheMaxSize = RequestCacheManager.getInstance().getDiskCacheMaxSize();
(5)清除全部緩存
RequestCacheManager.getInstance().deleteAllDiskCacheData();
⑨請求配置
在發送請求的時候,有的重載函數須要傳入一個RequestCacheConfig對象,不須要傳入此對象的重載函數內部傳入的是默認的 RequestCacheConfig對象,經過RequestCacheConfig對象控制緩存於網絡數據等,下面是默認的RequestCacheConfig配置
public static RequestCacheConfig buildDefaultCacheConfig() {
RequestCacheConfig cacheConfig=new RequestCacheConfig();
cacheConfig.setShouldCache(true); //開啓緩存
cacheConfig.setUseCacheDataAnyway(false); //關閉老是優先使用緩存
cacheConfig.setUseCacheDataWhenRequestFailed(true); //開啓請求失敗使用緩存
cacheConfig.setUseCacheDataWhenTimeout(false); //關閉超時使用緩存
cacheConfig.setUseCacheDataWhenUnexpired(true); //開啓當緩存未過時時使用緩存
cacheConfig.setRetryWhenRequestFailed(true); //開啓請求失敗重試
cacheConfig.setNeverExpired(false); //關閉緩存永不過時
TimeController timeController=new TimeController();
timeController.setExpirationTime(DEFAULT_EXPIRATION_TIME); //設置緩存的過時時間
timeController.setTimeout(DEFAULT_TIMEOUT); //設置緩存超時時間,對應「setUseCacheDataWhenTimeout」函數的超時時間
cacheConfig.setTimeController(timeController); //把時間控制器設置給RequestCacheConfig
return cacheConfig;
}
每次請求若是須要從新指定配置,本身構造這樣一個對象傳入便可
⑩原始發送請求方式
XRequest實際上是使用裝飾者模式,對一系列請求步驟進行了封裝,目的是爲了更簡單的使用,若是有複雜的需求,須要更高的自由度的話, 能夠參考以下發送請求代碼
MultipartGsonRequest<Bean> request = new MultipartGsonRequest<T>(cacheConfig, url, cacheKey, Bean.class, onRequestListener);
request.setRequestParams(params);
request.setHttpMethod(HttpMethod.POST);
request.setTag(tag);
XRequest.getInstance().addToRequestQueue(request);