package me.yoqi.android.jkbd.utils; import android.content.Context; import android.os.Handler; import android.os.Message; import android.util.Log; import com.google.gson.Gson; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.FileNameMap; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import okhttp3.Cache; import okhttp3.Call; import okhttp3.Callback; import okhttp3.FormBody; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * Created by yao on 2016/9/16. * */ public class OkHttpUtils { private static String UTF_8 = "utf-8"; public static final int RESULT_SUCCESS = 0; public static final int RESULT_ERROR = 1; public static final int DOWNLOAD_START=2; public static final int DOWNLOADING=3; public static final int DOWNLOAD_FINISH=4; private static OkHttpClient mOkHttpClient; private Handler mHandler; private String SERVER_ROOT; private Context mContext; public void setSERVER_ROOT(String SERVER_ROOT) { this.SERVER_ROOT = SERVER_ROOT; } public void setContext(Context context) { mContext = context; } /** * 存放post请求的实体,实体中存放File类型的文件 */ RequestBody mFileBody; FormBody.Builder mFormBodyBuilder; MultipartBody.Builder mMultipartBodyBuilder; public interface OnCompleteListener { void onSuccess(T result); void onError(String error); } private OnCompleteListener mListener; OkHttpClient.Builder mBuilder; /** * 构造器,mOkHttpClient必须单例,无论创建多少个OkHttpUtils的实例。 * 都由mOkHttpClient一个对象处理所有的网络请求。 */ public OkHttpUtils(Context context) { mContext = context; if (mOkHttpClient == null) {//线程安全的单例 synchronized (OkHttpUtils.class) { if (mOkHttpClient == null) { mBuilder = new OkHttpClient.Builder(); //获取sd卡的缓存文件夹 File cacheDir = context.getExternalCacheDir(); mOkHttpClient = mBuilder .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(20,TimeUnit.SECONDS) .readTimeout(10,TimeUnit.SECONDS) .cache(new Cache(cacheDir,10*(1<<20)))//设置缓存位置和缓存大小 .build(); } } } initHandler(); } /** * 设置与服务端连接的时限 * @param connectTime:连接的时限 * @return */ public OkHttpUtils connectTimeout(int connectTime) { if (mBuilder == null) { return this; } mBuilder.connectTimeout(connectTime, TimeUnit.SECONDS); return this; } /** * 设置写数据的时限 * @param writeTimeout:写数据的时限 * @return */ public OkHttpUtils writeTimeout(int writeTimeout) { if (mBuilder == null) { return this; } mBuilder.writeTimeout(writeTimeout, TimeUnit.SECONDS); return this; } /** * 设置读取数据的时限 * @param readTimeout:读取数据的时限 * @return */ public OkHttpUtils readTimeout(int readTimeout) { if (mBuilder == null) { return this; } mBuilder.readTimeout(readTimeout, TimeUnit.SECONDS); return this; } /** * 设置缓存 * 第一次请求会请求网络得到数据,第二次以及后面的请求则会从缓存中取出数据 * @param file:缓存的路径 * @param fileSize:缓存的容量 * @return */ public OkHttpUtils cache(File file, int fileSize) { if (mBuilder == null) { return this; } mBuilder.cache(new Cache(file, fileSize)); return this; } private void initHandler() { mHandler = new Handler(mContext.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case RESULT_ERROR: mListener.onError(msg.obj==null?msg.toString():msg.obj.toString()); break; case RESULT_SUCCESS: T result = (T) msg.obj; mListener.onSuccess(result); break; } } }; } /** * 用post请求,添加一个文件 * @param file:添加至form的文件 * @return */ public OkHttpUtils addFile(File file) { mFileBody = RequestBody.create(null, file); return this; } /** * 支持设置媒体文件类型的addFile * @param type:媒体类型 * @param file:添加至form的文件 * @return */ public OkHttpUtils addFile(String type, File file) { mFileBody = RequestBody.create(MediaType.parse(type), file); return this; } public OkHttpUtils addFile2(File file) { if (mUrl == null) { return this; } RequestBody fileBody = RequestBody.create(MediaType.parse(guessMimeType(file.getName())), file); mFileBody = new MultipartBody.Builder().addFormDataPart("filename", file.getName(), fileBody).build(); return this; } private String guessMimeType(String path) { FileNameMap fileNameMap = URLConnection.getFileNameMap(); String contentTypeFor = fileNameMap.getContentTypeFor(path); if (contentTypeFor == null) { contentTypeFor = "application/octet-stream"; } return contentTypeFor; } /** * 设置为post的请求 * @return */ public OkHttpUtils post() { mFormBodyBuilder = new FormBody.Builder(); return this; } StringBuilder mUrl; public OkHttpUtils url(String url) { mUrl = new StringBuilder(url); return this; } public OkHttpUtils setRequestUrl(String request) { //http://101.251.196.90:8080/JztkServer/examInfo //http://120.26.242.249:8080/SuperWeChatServerV2.0/register?m_user_name=aaaaaa&m_user_nick=aaaaaa&m_user_password=aaaaaa mUrl = new StringBuilder(SERVER_ROOT); mUrl.append(request); // Log.e("okhttp","1 murl="+ mUrl.toString()); return this; } /** * 用于json解析的类对象 */ Class mClazz; /** * 设置json解析的目标类对象 * @param clazz:解析的类对象 * @return */ public OkHttpUtils targetClass(Class clazz) { mClazz = clazz; return this; } /** * 添加请求参数至url,包括GET和POST请求 * 不包括POST请求中上传文件的同时向Form中添加其它参数的情况 * @param key:键 * @param value:值 */ public OkHttpUtils addParam(String key, String value) { try { //post请求的request参数也要拼接到url中 if (mFormBodyBuilder != null) {//post请求的参数添加方式 mFormBodyBuilder.add(key, URLEncoder.encode(value, UTF_8)); } else {//get请求的参数添加方式 if (mUrl.indexOf("?") == -1) { mUrl.append("?"); } else { mUrl.append("&"); } mUrl.append(key).append("=").append(URLEncoder.encode(value, UTF_8)); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return this; } /** * * post请求,上传文件的同时允许在Form中添加多个参数 * @param key:参数的键 * @param value:参数的值 * @return */ public OkHttpUtils addFormParam(String key, String value) { if (mMultipartBodyBuilder == null) { mMultipartBodyBuilder =new MultipartBody.Builder(); mMultipartBodyBuilder.setType(MultipartBody.FORM); try { mUrl.append("?") .append(key) .append("=") .append(URLEncoder.encode(value, UTF_8)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }else if (mUrl.indexOf("?") > -1) { mMultipartBodyBuilder.addFormDataPart(key, value); } return this; } /** * post请求中在Form中添加包含上传文件的多个参数 * @param name:文件的大类型 * @param fileName:文件名包括扩展名 * @param mediaType:文件的媒体类型 * @param file:文件 * @return */ public OkHttpUtils addFormParam(String name, String fileName, String mediaType, File file) { if (mMultipartBodyBuilder == null) { return this; } mMultipartBodyBuilder.addFormDataPart(name, fileName, RequestBody.create(MediaType.parse(mediaType), file)); return this; } /** * 发送请求 * @param listener:处理服务端返回结果的代码 */ public void execute(OnCompleteListener listener) { if (listener != null) { mListener = listener; } Request.Builder builder = new Request.Builder().url(mUrl.toString()); Log.e("OKHttp","url="+mUrl); if (mFormBodyBuilder != null) { RequestBody body = mFormBodyBuilder.build(); builder.post(body); } if (mFileBody != null) { builder.post(mFileBody); } //如果是post请求向Form中添加多个参数 if (mMultipartBodyBuilder != null) { MultipartBody multipartBody = mMultipartBodyBuilder.build(); builder.post(multipartBody); } //创建请求 Request request = builder.build(); Call call = mOkHttpClient.newCall(request); if (mCallback != null) { call.enqueue(mCallback); return; } call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Message msg = Message.obtain(); msg.what = RESULT_ERROR; msg.obj = e.getMessage(); mHandler.sendMessage(msg); } @Override public void onResponse(Call call, Response response) throws IOException { String json = response.body().string(); if (mClazz==null){ targetClass((Class) String.class); } if(mClazz.equals(String.class)){ Message msg = Message.obtain(); msg.what = RESULT_SUCCESS; msg.obj = json; mHandler.sendMessage(msg); }else { Gson gson = new Gson(); T value = gson.fromJson(json, mClazz); Message msg = Message.obtain(); msg.what = RESULT_SUCCESS; msg.obj = value; mHandler.sendMessage(msg); } } }); } Callback mCallback; /** * 在OkHttp创建的工作线程中执行一段代码, * @param callback * @return */ public OkHttpUtils doInBackground(Callback callback) { mCallback=callback; return this; } /** * 在主线程中执行的代码,doInBackground方法之后调用 * @param listener * @return */ public OkHttpUtils onPostExecute(OnCompleteListener listener) { mListener=listener; return this; } /**doInBackground()之前在主线程中执行的方法,类似与AsyncTask中的onPreExecute() * @param r:运行的代码 * @return */ public OkHttpUtils onPreExecute(Runnable r) { r.run(); return this; } /** * 工作线程向主线程发送消息 * @param msg */ public void sendMessage(Message msg) { mHandler.sendMessage(msg); } /** * 重载的sendMessage方法,用于发送空消息 * @param what */ public void sendMessage(int what) { mHandler.sendEmptyMessage(what); } public T parseJson(String json, Class clazz) { Gson gson=new Gson(); T t = (T) gson.fromJson(json, clazz); return t; } /** * 专门针对Result类的json解析方法,不具有通用性,属性定制、专用的方法 * @param result * @param clazz * @param * @return */ // public T parseJson(Result result, Class clazz) { // if (result.getRetCode() == 0) { // String json = result.getRetData().toString(); // T t = parseJson(json, clazz); // return t; // } // return null; // } /** * 下载文件,支持更新下载进度 * @param response:服务端返回的响应类对象 * @param file:保存下载文件的File * @throws Exception:IO异常 */ public void downloadFile(Response response, File file) throws Exception { FileOutputStream out = new FileOutputStream(file); InputStream in = response.body().byteStream(); int len; byte[] buffer = new byte[1024 * 5]; //获取文件的字节数 long fileSize = response.body().contentLength(); int total=0;//累加下载的字节数 int percent=1;//下载的预期百分比 int currentPer;//当前下载的百分比 mHandler.sendEmptyMessage(DOWNLOAD_START); while ((len=in.read(buffer)) != -1) { out.write(buffer,0,len); total+=len; //计算下载的百分比 currentPer= (int) (total*100L/fileSize); if (currentPer >= percent) { Message msg = Message.obtain(); msg.what= OkHttpUtils.DOWNLOADING; msg.arg1=percent; sendMessage(msg); percent=currentPer+1; } } sendMessage(OkHttpUtils.DOWNLOAD_FINISH); } public ArrayList array2List(T[] array) { List list = Arrays.asList(array); ArrayList arrayList = new ArrayList<>(list); return arrayList; } /** * 释放mClient的资源 */ public static void release() { if (mOkHttpClient != null) { //取消所有请求 mOkHttpClient.dispatcher().cancelAll(); mOkHttpClient=null; } } }