OkHttpUtils.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. package me.yoqi.android.jkbd.utils;
  2. import android.content.Context;
  3. import android.os.Handler;
  4. import android.os.Message;
  5. import android.util.Log;
  6. import com.google.gson.Gson;
  7. import java.io.File;
  8. import java.io.FileOutputStream;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.UnsupportedEncodingException;
  12. import java.net.FileNameMap;
  13. import java.net.URLConnection;
  14. import java.net.URLEncoder;
  15. import java.util.ArrayList;
  16. import java.util.Arrays;
  17. import java.util.List;
  18. import java.util.concurrent.TimeUnit;
  19. import okhttp3.Cache;
  20. import okhttp3.Call;
  21. import okhttp3.Callback;
  22. import okhttp3.FormBody;
  23. import okhttp3.MediaType;
  24. import okhttp3.MultipartBody;
  25. import okhttp3.OkHttpClient;
  26. import okhttp3.Request;
  27. import okhttp3.RequestBody;
  28. import okhttp3.Response;
  29. /**
  30. * Created by yao on 2016/9/16.
  31. *
  32. */
  33. public class OkHttpUtils<T> {
  34. private static String UTF_8 = "utf-8";
  35. public static final int RESULT_SUCCESS = 0;
  36. public static final int RESULT_ERROR = 1;
  37. public static final int DOWNLOAD_START=2;
  38. public static final int DOWNLOADING=3;
  39. public static final int DOWNLOAD_FINISH=4;
  40. private static OkHttpClient mOkHttpClient;
  41. private Handler mHandler;
  42. private String SERVER_ROOT;
  43. private Context mContext;
  44. public void setSERVER_ROOT(String SERVER_ROOT) {
  45. this.SERVER_ROOT = SERVER_ROOT;
  46. }
  47. public void setContext(Context context) {
  48. mContext = context;
  49. }
  50. /**
  51. * 存放post请求的实体,实体中存放File类型的文件
  52. */
  53. RequestBody mFileBody;
  54. FormBody.Builder mFormBodyBuilder;
  55. MultipartBody.Builder mMultipartBodyBuilder;
  56. public interface OnCompleteListener<T> {
  57. void onSuccess(T result);
  58. void onError(String error);
  59. }
  60. private OnCompleteListener<T> mListener;
  61. OkHttpClient.Builder mBuilder;
  62. /**
  63. * 构造器,mOkHttpClient必须单例,无论创建多少个OkHttpUtils的实例。
  64. * 都由mOkHttpClient一个对象处理所有的网络请求。
  65. */
  66. public OkHttpUtils(Context context) {
  67. mContext = context;
  68. if (mOkHttpClient == null) {//线程安全的单例
  69. synchronized (OkHttpUtils.class) {
  70. if (mOkHttpClient == null) {
  71. mBuilder = new OkHttpClient.Builder();
  72. //获取sd卡的缓存文件夹
  73. File cacheDir = context.getExternalCacheDir();
  74. mOkHttpClient = mBuilder
  75. .connectTimeout(10, TimeUnit.SECONDS)
  76. .writeTimeout(20,TimeUnit.SECONDS)
  77. .readTimeout(10,TimeUnit.SECONDS)
  78. .cache(new Cache(cacheDir,10*(1<<20)))//设置缓存位置和缓存大小
  79. .build();
  80. }
  81. }
  82. }
  83. initHandler();
  84. }
  85. /**
  86. * 设置与服务端连接的时限
  87. * @param connectTime:连接的时限
  88. * @return
  89. */
  90. public OkHttpUtils<T> connectTimeout(int connectTime) {
  91. if (mBuilder == null) {
  92. return this;
  93. }
  94. mBuilder.connectTimeout(connectTime, TimeUnit.SECONDS);
  95. return this;
  96. }
  97. /**
  98. * 设置写数据的时限
  99. * @param writeTimeout:写数据的时限
  100. * @return
  101. */
  102. public OkHttpUtils<T> writeTimeout(int writeTimeout) {
  103. if (mBuilder == null) {
  104. return this;
  105. }
  106. mBuilder.writeTimeout(writeTimeout, TimeUnit.SECONDS);
  107. return this;
  108. }
  109. /**
  110. * 设置读取数据的时限
  111. * @param readTimeout:读取数据的时限
  112. * @return
  113. */
  114. public OkHttpUtils<T> readTimeout(int readTimeout) {
  115. if (mBuilder == null) {
  116. return this;
  117. }
  118. mBuilder.readTimeout(readTimeout, TimeUnit.SECONDS);
  119. return this;
  120. }
  121. /**
  122. * 设置缓存
  123. * 第一次请求会请求网络得到数据,第二次以及后面的请求则会从缓存中取出数据
  124. * @param file:缓存的路径
  125. * @param fileSize:缓存的容量
  126. * @return
  127. */
  128. public OkHttpUtils<T> cache(File file, int fileSize) {
  129. if (mBuilder == null) {
  130. return this;
  131. }
  132. mBuilder.cache(new Cache(file, fileSize));
  133. return this;
  134. }
  135. private void initHandler() {
  136. mHandler = new Handler(mContext.getMainLooper()) {
  137. @Override
  138. public void handleMessage(Message msg) {
  139. switch (msg.what) {
  140. case RESULT_ERROR:
  141. mListener.onError(msg.obj==null?msg.toString():msg.obj.toString());
  142. break;
  143. case RESULT_SUCCESS:
  144. T result = (T) msg.obj;
  145. mListener.onSuccess(result);
  146. break;
  147. }
  148. }
  149. };
  150. }
  151. /**
  152. * 用post请求,添加一个文件
  153. * @param file:添加至form的文件
  154. * @return
  155. */
  156. public OkHttpUtils<T> addFile(File file) {
  157. mFileBody = RequestBody.create(null, file);
  158. return this;
  159. }
  160. /**
  161. * 支持设置媒体文件类型的addFile
  162. * @param type:媒体类型
  163. * @param file:添加至form的文件
  164. * @return
  165. */
  166. public OkHttpUtils<T> addFile(String type, File file) {
  167. mFileBody = RequestBody.create(MediaType.parse(type), file);
  168. return this;
  169. }
  170. public OkHttpUtils<T> addFile2(File file) {
  171. if (mUrl == null) {
  172. return this;
  173. }
  174. RequestBody fileBody = RequestBody.create(MediaType.parse(guessMimeType(file.getName())), file);
  175. mFileBody = new MultipartBody.Builder().addFormDataPart("filename", file.getName(), fileBody).build();
  176. return this;
  177. }
  178. private String guessMimeType(String path) {
  179. FileNameMap fileNameMap = URLConnection.getFileNameMap();
  180. String contentTypeFor = fileNameMap.getContentTypeFor(path);
  181. if (contentTypeFor == null)
  182. {
  183. contentTypeFor = "application/octet-stream";
  184. }
  185. return contentTypeFor;
  186. }
  187. /**
  188. * 设置为post的请求
  189. * @return
  190. */
  191. public OkHttpUtils<T> post() {
  192. mFormBodyBuilder = new FormBody.Builder();
  193. return this;
  194. }
  195. StringBuilder mUrl;
  196. public OkHttpUtils<T> url(String url) {
  197. mUrl = new StringBuilder(url);
  198. return this;
  199. }
  200. public OkHttpUtils<T> setRequestUrl(String request) {
  201. //http://101.251.196.90:8080/JztkServer/examInfo
  202. //http://120.26.242.249:8080/SuperWeChatServerV2.0/register?m_user_name=aaaaaa&m_user_nick=aaaaaa&m_user_password=aaaaaa
  203. mUrl = new StringBuilder(SERVER_ROOT);
  204. mUrl.append(request);
  205. // Log.e("okhttp","1 murl="+ mUrl.toString());
  206. return this;
  207. }
  208. /**
  209. * 用于json解析的类对象
  210. */
  211. Class<T> mClazz;
  212. /**
  213. * 设置json解析的目标类对象
  214. * @param clazz:解析的类对象
  215. * @return
  216. */
  217. public OkHttpUtils<T> targetClass(Class<T> clazz) {
  218. mClazz = clazz;
  219. return this;
  220. }
  221. /**
  222. * 添加请求参数至url,包括GET和POST请求
  223. * 不包括POST请求中上传文件的同时向Form中添加其它参数的情况
  224. * @param key:键
  225. * @param value:值
  226. */
  227. public OkHttpUtils<T> addParam(String key, String value) {
  228. try {
  229. //post请求的request参数也要拼接到url中
  230. if (mFormBodyBuilder != null) {//post请求的参数添加方式
  231. mFormBodyBuilder.add(key, URLEncoder.encode(value, UTF_8));
  232. } else {//get请求的参数添加方式
  233. if (mUrl.indexOf("?") == -1) {
  234. mUrl.append("?");
  235. } else {
  236. mUrl.append("&");
  237. }
  238. mUrl.append(key).append("=").append(URLEncoder.encode(value, UTF_8));
  239. }
  240. } catch (UnsupportedEncodingException e) {
  241. e.printStackTrace();
  242. }
  243. return this;
  244. }
  245. /**
  246. * * post请求,上传文件的同时允许在Form中添加多个参数
  247. * @param key:参数的键
  248. * @param value:参数的值
  249. * @return
  250. */
  251. public OkHttpUtils<T> addFormParam(String key, String value) {
  252. if (mMultipartBodyBuilder == null) {
  253. mMultipartBodyBuilder =new MultipartBody.Builder();
  254. mMultipartBodyBuilder.setType(MultipartBody.FORM);
  255. try {
  256. mUrl.append("?")
  257. .append(key)
  258. .append("=")
  259. .append(URLEncoder.encode(value, UTF_8));
  260. } catch (UnsupportedEncodingException e) {
  261. e.printStackTrace();
  262. }
  263. }else if (mUrl.indexOf("?") > -1) {
  264. mMultipartBodyBuilder.addFormDataPart(key, value);
  265. }
  266. return this;
  267. }
  268. /**
  269. * post请求中在Form中添加包含上传文件的多个参数
  270. * @param name:文件的大类型
  271. * @param fileName:文件名包括扩展名
  272. * @param mediaType:文件的媒体类型
  273. * @param file:文件
  274. * @return
  275. */
  276. public OkHttpUtils<T> addFormParam(String name, String fileName, String mediaType, File file) {
  277. if (mMultipartBodyBuilder == null) {
  278. return this;
  279. }
  280. mMultipartBodyBuilder.addFormDataPart(name, fileName, RequestBody.create(MediaType.parse(mediaType), file));
  281. return this;
  282. }
  283. /**
  284. * 发送请求
  285. * @param listener:处理服务端返回结果的代码
  286. */
  287. public void execute(OnCompleteListener<T> listener) {
  288. if (listener != null) {
  289. mListener = listener;
  290. }
  291. Request.Builder builder = new Request.Builder().url(mUrl.toString());
  292. Log.e("OKHttp","url="+mUrl);
  293. if (mFormBodyBuilder != null) {
  294. RequestBody body = mFormBodyBuilder.build();
  295. builder.post(body);
  296. }
  297. if (mFileBody != null) {
  298. builder.post(mFileBody);
  299. }
  300. //如果是post请求向Form中添加多个参数
  301. if (mMultipartBodyBuilder != null) {
  302. MultipartBody multipartBody = mMultipartBodyBuilder.build();
  303. builder.post(multipartBody);
  304. }
  305. //创建请求
  306. Request request = builder.build();
  307. Call call = mOkHttpClient.newCall(request);
  308. if (mCallback != null) {
  309. call.enqueue(mCallback);
  310. return;
  311. }
  312. call.enqueue(new Callback() {
  313. @Override
  314. public void onFailure(Call call, IOException e) {
  315. Message msg = Message.obtain();
  316. msg.what = RESULT_ERROR;
  317. msg.obj = e.getMessage();
  318. mHandler.sendMessage(msg);
  319. }
  320. @Override
  321. public void onResponse(Call call, Response response) throws IOException {
  322. String json = response.body().string();
  323. if (mClazz==null){
  324. targetClass((Class<T>) String.class);
  325. }
  326. if(mClazz.equals(String.class)){
  327. Message msg = Message.obtain();
  328. msg.what = RESULT_SUCCESS;
  329. msg.obj = json;
  330. mHandler.sendMessage(msg);
  331. }else {
  332. Gson gson = new Gson();
  333. T value = gson.fromJson(json, mClazz);
  334. Message msg = Message.obtain();
  335. msg.what = RESULT_SUCCESS;
  336. msg.obj = value;
  337. mHandler.sendMessage(msg);
  338. }
  339. }
  340. });
  341. }
  342. Callback mCallback;
  343. /**
  344. * 在OkHttp创建的工作线程中执行一段代码,
  345. * @param callback
  346. * @return
  347. */
  348. public OkHttpUtils<T> doInBackground(Callback callback) {
  349. mCallback=callback;
  350. return this;
  351. }
  352. /**
  353. * 在主线程中执行的代码,doInBackground方法之后调用
  354. * @param listener
  355. * @return
  356. */
  357. public OkHttpUtils<T> onPostExecute(OnCompleteListener<T> listener) {
  358. mListener=listener;
  359. return this;
  360. }
  361. /**doInBackground()之前在主线程中执行的方法,类似与AsyncTask中的onPreExecute()
  362. * @param r:运行的代码
  363. * @return
  364. */
  365. public OkHttpUtils<T> onPreExecute(Runnable r) {
  366. r.run();
  367. return this;
  368. }
  369. /**
  370. * 工作线程向主线程发送消息
  371. * @param msg
  372. */
  373. public void sendMessage(Message msg) {
  374. mHandler.sendMessage(msg);
  375. }
  376. /**
  377. * 重载的sendMessage方法,用于发送空消息
  378. * @param what
  379. */
  380. public void sendMessage(int what) {
  381. mHandler.sendEmptyMessage(what);
  382. }
  383. public <T> T parseJson(String json, Class<?> clazz) {
  384. Gson gson=new Gson();
  385. T t = (T) gson.fromJson(json, clazz);
  386. return t;
  387. }
  388. /**
  389. * 专门针对Result类的json解析方法,不具有通用性,属性定制、专用的方法
  390. * @param result
  391. * @param clazz
  392. * @param <T>
  393. * @return
  394. */
  395. // public <T> T parseJson(Result result, Class<?> clazz) {
  396. // if (result.getRetCode() == 0) {
  397. // String json = result.getRetData().toString();
  398. // T t = parseJson(json, clazz);
  399. // return t;
  400. // }
  401. // return null;
  402. // }
  403. /**
  404. * 下载文件,支持更新下载进度
  405. * @param response:服务端返回的响应类对象
  406. * @param file:保存下载文件的File
  407. * @throws Exception:IO异常
  408. */
  409. public void downloadFile(Response response, File file) throws Exception {
  410. FileOutputStream out = new FileOutputStream(file);
  411. InputStream in = response.body().byteStream();
  412. int len;
  413. byte[] buffer = new byte[1024 * 5];
  414. //获取文件的字节数
  415. long fileSize = response.body().contentLength();
  416. int total=0;//累加下载的字节数
  417. int percent=1;//下载的预期百分比
  418. int currentPer;//当前下载的百分比
  419. mHandler.sendEmptyMessage(DOWNLOAD_START);
  420. while ((len=in.read(buffer)) != -1) {
  421. out.write(buffer,0,len);
  422. total+=len;
  423. //计算下载的百分比
  424. currentPer= (int) (total*100L/fileSize);
  425. if (currentPer >= percent) {
  426. Message msg = Message.obtain();
  427. msg.what= OkHttpUtils.DOWNLOADING;
  428. msg.arg1=percent;
  429. sendMessage(msg);
  430. percent=currentPer+1;
  431. }
  432. }
  433. sendMessage(OkHttpUtils.DOWNLOAD_FINISH);
  434. }
  435. public <T> ArrayList<T> array2List(T[] array) {
  436. List<T> list = Arrays.asList(array);
  437. ArrayList<T> arrayList = new ArrayList<>(list);
  438. return arrayList;
  439. }
  440. /**
  441. * 释放mClient的资源
  442. */
  443. public static void release() {
  444. if (mOkHttpClient != null) {
  445. //取消所有请求
  446. mOkHttpClient.dispatcher().cancelAll();
  447. mOkHttpClient=null;
  448. }
  449. }
  450. }