本人分成了四个类,其实可以更加精简,两个类足以
首先引入依赖 okhttp github地址
implementation("com.squareup.okhttp3:okhttp:3.14.2")
上代码,首先展示一下请求代码(Kotlin)
OkHttp.post("url") //请求地址和请求方式,get和post方式切换
.add(map) //参数可以直接传入map集合
.add("key","value") //参数也可以传入键值对
.build(object : HttpCallBack() { //传入返回的实体类
override fun success(t: T?) {
//得到返回的实体类
}
override fun error(err: String?) {
//得到错误信息提醒
}
})
以上就是请求示例代码,够简单了吧,当然这都是表面的,下面来看一下背后做的工作
上关键类 OkHttp :
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import com.toune.util.rxtool.GsonBinder;
import com.toune.util.rxtool.RxFileTool;
import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
public class OkHttp {
private static int METHOD = 1000;
private static final int POST = 1001;
private static final int GET = 1002;
private static OkHttp okHttp;
private File updateFile;
public static void instance() {
okHttp = new OkHttp();
}
private static OkHttpClient okHttpClient;
private static RequestBody requestBody;
private static Request request;
private static String requestUrl;
public static OkHttp post(String url) {
instance();
okHttpClient = new OkHttpClient();
METHOD = POST;
requestUrl = url;
return okHttp;
}
public static OkHttp get(String url) {
instance();
okHttpClient = new OkHttpClient();
METHOD = GET;
requestUrl = url;
return okHttp;
}
private Map params = new HashMap();
private Map files = new HashMap<>();
public OkHttp add(String key, Object value) {
params.put(key, String.valueOf(value));
return this;
}
public OkHttp add(Map map) {
params.putAll(map);
return this;
}
public OkHttp add(String key, File file) {
files.put(key, file);
return this;
}
private int BUILD_TYPE = 300;
private final int JSON_TYPE = 301;
private final int FILE_TYPE = 302;
private MediaType JSONType = MediaType.parse("application/json; charset=utf-8");
public void buildByJson(final HttpCallBack httpCallBack) {
BUILD_TYPE = JSON_TYPE;
build(httpCallBack);
}
/**
* 基于http的文件上传(传入文件数组和key)混合参数和文件请求
* 通过addFormDataPart可以添加多个上传的文件
*/
private void buidByFile(final HttpCallBack myDataCallBack) {
if (params == null) {
params = new HashMap<>();
}
FormBody.Builder builder = new FormBody.Builder();
//form表单提交
for (String key : params.keySet()) {
builder.add(key, (String) params.get(key));
}
RequestBody body = builder.build();
MultipartBody.Builder multipartBody = new MultipartBody.Builder();
multipartBody.setType(MultipartBody.ALTERNATIVE)
.addPart(body);
if (files != null) {
RequestBody fileBody = null;
for (String key : files.keySet()) {
File file = files.get(key);
String fileName = file.getName();
fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
//TODO 根据文件名设置contentType
multipartBody.addPart(Headers.of("Content-Disposition",
"form-data; name=\"" + key + "\"; filename=\"" + fileName + "\""),
fileBody);
}
}
requestBody = multipartBody.build();
BUILD_TYPE = FILE_TYPE;
}
private String guessMimeType(String fileName) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(fileName);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
public void build(final HttpCallBack httpCallBack) {
this.httpCallBack = httpCallBack;
handler.sendEmptyMessage(START);
switch (BUILD_TYPE) {
case JSON_TYPE: //json提交
requestBody = RequestBody.create(JSONType, GsonBinder.toJsonStr(params));
break;
case FILE_TYPE:
break;
default:
//form表单提交
FormBody.Builder builder = new FormBody.Builder();
for (String key : params.keySet()) {
builder.add(key, (String) params.get(key));
}
requestBody = builder.build();
break;
}
if (METHOD == GET) {
request = new Request.Builder()
.url(requestUrl)
.get()//默认就是GET请求,可以不写
.build();
} else if (METHOD == POST) {
request = new Request.Builder()
.url(requestUrl)
.post(requestBody)
.build();
}
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Message message = new Message();
message.obj = e.getMessage();
message.what = ERROR;
handler.sendMessage(message);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
String jsonStr = response.body().string();
JSONObject jsonObject = new JSONObject(jsonStr);
String msg = "";
if (jsonObject.has("info")) {
msg = jsonObject.getString("info");
}
if (jsonObject.has("status")) {
String status = jsonObject.getString("status");
if ("1".equals(status)) {
//成功
if (jsonObject.has("data")) {
T data = GsonBinder.toObj(jsonObject.getString("data"),httpCallBack.mType);
response.close();
Message message = new Message();
message.obj = data;
message.what = SUCCESS;
handler.sendMessage(message);
}
} else if ("0".equals(status)) {
//错误
Message message = new Message();
message.obj = msg;
message.what = ERROR;
handler.sendMessage(message);
} else {
Message message = new Message();
message.obj = msg;
message.what = ERROR;
handler.sendMessage(message);
}
}
} catch (Exception e) {
e.printStackTrace();
handler.sendEmptyMessage(END);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
handler.sendEmptyMessage(END);
}
});
}
private HttpCallBack httpCallBack;
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case START:
httpCallBack.start();
break;
case SUCCESS:
httpCallBack.success(msg.obj);
break;
case ERROR:
if (msg.obj != null) {
httpCallBack.error(msg.obj.toString());
}
httpCallBack.end();
break;
case END:
httpCallBack.end();
break;
}
}
};
private final int START = 10001;
private final int SUCCESS = 10002;
private final int ERROR = 10003;
private final int END = 10004;
/**
* 下载文件******************************************************************************************************************************************
*/
/**
* 文件下载
*
* @param url path路径
* @param destFileDir 本地存储的文件夹路径
* @param myDataCallBack 自定义回调接口
*/
private static String downUrl;
private static String filrDir;
private long totalSize = 0L; //APK总大小
private long downloadSize = 0L; // 下载的大小
private float count = 0L; //下载百分比
public static OkHttp downFile(String realURL, String destFileDir) {
instance();
downUrl = realURL;
filrDir = destFileDir;
return okHttp;
}
public void down(HttpFileCallBack httpFileCallBack) {
this.httpFileCallBack = httpFileCallBack;
Request request = new Request.Builder()
.url(downUrl)
.build();
okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Message message = new Message();
message.obj = e.getMessage();
message.what = ERROR;
fileHandler.sendMessage(message);
}
@Override
public void onResponse(Call call, Response response) {
if (response.code() == 200) {
InputStream is = null;
byte[] buf = new byte[4096];
int len = 0;
FileOutputStream fos = null;
try {
totalSize = response.body().contentLength();
downloadSize = 0L;
if (memoryAvailable(totalSize)) {
is = response.body().byteStream();
fos = new FileOutputStream(updateFile, true);
while ((len = is.read(buf)) != -1) {
downloadSize += len;
fos.write(buf, 0, len);
if ((count == 0) || (int) (downloadSize * 100 / totalSize) >= count) {
count += 5;
//文本进度(百分比)
Message message = new Message();
message.obj = count;
message.what = FILE_PROGRESS;
}
}
fos.flush();
if (totalSize >= downloadSize) {
fileHandler.sendEmptyMessage(SUCCESS);
} else {
Message message = new Message();
message.obj = "下载失败";
message.what = ERROR;
fileHandler.sendMessage(message);
}
} else {
Message message = new Message();
message.obj = "内存不足";
message.what = ERROR;
fileHandler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
Message message = new Message();
message.obj = "下载失败";
message.what = ERROR;
fileHandler.sendMessage(message);
} finally {
try {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
Message message = new Message();
message.obj = "下载失败";
message.what = ERROR;
fileHandler.sendMessage(message);
}
}
});
}
private String getFileName(String url) {
int separatorIndex = url.lastIndexOf("/");
return (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());
}
/**
* 可用内存大小
*
* @param fileSize
* @return
*/
private boolean memoryAvailable(long fileSize) {
fileSize += (1024 << 10);
if (MemoryStatus.externalMemoryAvailable()) {
if ((MemoryStatus.getAvailableExternalMemorySize() <= fileSize)) {
if ((MemoryStatus.getAvailableInternalMemorySize() > fileSize)) {
createFile(false);
return true;
} else {
return false;
}
} else {
createFile(true);
return true;
}
} else {
if (MemoryStatus.getAvailableInternalMemorySize() <= fileSize) {
return false;
} else {
createFile(false);
return true;
}
}
}
private void createFile(boolean b) {
RxFileTool.createFileByDeleteOldFile(filrDir + getFileName(downUrl));
updateFile = RxFileTool.getFileByPath(filrDir + getFileName(downUrl));
}
private HttpFileCallBack httpFileCallBack;
Handler fileHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FILE_START:
httpFileCallBack.start();
break;
case FILE_PROGRESS:
httpFileCallBack.progress((int) msg.obj);
break;
case FILE_SUCCESS:
httpFileCallBack.success(updateFile);
break;
case FILE_ERROR:
if (msg.obj != null) {
httpFileCallBack.error(msg.obj.toString());
}
httpFileCallBack.end();
break;
case FILE_END:
httpFileCallBack.end();
break;
}
}
};
private final int FILE_START = 100001;
private final int FILE_SUCCESS = 100002;
private final int FILE_ERROR = 100003;
private final int FILE_END = 100004;
private static final int FILE_PROGRESS = 100005;
/***************************************************************下载完文件*******************************************************************/
}
这个类中,我做了符合我们项目的深度配置,但是大部分项目都差不多,所以如果需要适配你们的项目只需要修改
TIM截图20190803101224.png
这个部分就可以了
上配套类 HttpCallBack
import com.google.gson.internal.$Gson$Types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class HttpCallBack {
public Type mType;
public HttpCallBack() {
//Type是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
// throw new RuntimeException("请传入实体类");
mType = null;
} else {
//ParameterizedType参数化类型,即泛型
ParameterizedType parameterized = (ParameterizedType) superclass;
//getActualTypeArguments获取参数化类型的数组,泛型可能有多个
//将Java 中的Type实现,转化为自己内部的数据实现,得到gson解析需要的泛型
mType = $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
}
public void start() {
}
public abstract void success(T t);
public abstract void error(String err);
public void end() {
}
}
这是数据返回类,可以在这里面修改需要实现的方法
为了更清晰,我把文件下载做了单独的返回
import java.io.File;
/**
* 下载文件返回
*/
public abstract class HttpFileCallBack {
public void start() {
}
public abstract void progress(int size);
public abstract void success(File file);
public abstract void error(String err);
public void end() {
}
}
还有内存管理工具类
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import java.io.File;
/**
* 完成代码的健壮性,其实现在的Android手机的储存都的够用的。
* 一般不会没有空间,有这个类来判断就更健壮一些
*/
public class MemoryStatus {
private static final int ERROR = -1;
// 判断SD卡是否存在?
static public boolean externalMemoryAvailable() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
// 获取内部存储器有用空间大小?
static public long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
// 获取内部存储器空间的大小
static public long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
// 获取SD卡有用空间大小,错误返回-1
static public long getAvailableExternalMemorySize() {
if (externalMemoryAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
} else {
return ERROR;
}
}
// 获取SD卡的空间大小,错误返码1
static public long getTotalExternalMemorySize() {
if (externalMemoryAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
} else {
return ERROR;
}
}
/**
* 根据给定的文件的路径来计算文件夹的大小
*
* @param dir 文件的路径
* @return 文件夹的大小
*/
static public long getFileSize(File dir) {
if (dir == null) {
return 0;
}
if (!dir.isDirectory()) {
return 0;
}
long dirSize = 0;
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
dirSize += file.length();
} else if (file.isDirectory()) {
dirSize += getFileSize(file); //如果是目标那就进行递归 来计算文件的大小
}
}
return dirSize;
}
// 把文件大小转化字符串
static public String formatSize(long size) {
Log.d("WL-gui", "文件的大小为:" + size);
String suffix = null;
if (size == 0) {
return "";
}
if (size >= 1024) {
suffix = "KB";
size /= 1024;
if (size >= 1024) {
suffix = "MB";
size /= 1024;
if (size >= 1024) {
suffix = "G";
size /= 1024;
}
}
}
StringBuilder resultBuffer = new StringBuilder(Long.toString(size));
int commaOffset = resultBuffer.length() - 3;
while (commaOffset > 0) {
resultBuffer.insert(commaOffset, ',');
commaOffset -= 3;
}
if (suffix != null)
resultBuffer.append(suffix);
return resultBuffer.toString();
}
}
GsonBinder类
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Administrator on 2018/1/11 0011.
*/
public class GsonBinder {
//定义并配置gson
private static final Gson gson = new GsonBuilder()//建造者模式设置不同的配置
.serializeNulls()//序列化为null对象
.setDateFormat("yyyy-MM-dd HH:mm:ss") //设置日期的格式
.disableHtmlEscaping()//防止对网址乱码 忽略对特殊字符的转换
.registerTypeAdapter(String.class, new StringConverter())//对为null的字段进行转换
.create();
/**
* 对解析数据的形式进行转换
*
* @param obj 解析的对象
* @return 转化结果为json字符串
*/
public static String toJsonStr(Object obj) {
if (obj == null) {
return "";
}
try {
return gson.toJson(obj);
} catch (Exception e) {
return "";
}
}
/**
* 解析为一个具体的对象
*
* @param json 要解析的字符串
* @param obj 要解析的对象
* @param 将json字符串解析成obj类型的对象
* @return
*/
public static T toObj(String json, Class obj) {
//如果为null直接返回为null
if (obj == null || TextUtils.isEmpty(json)) {
return null;
}
try {
return gson.fromJson(json, obj);
} catch (Exception e) {
return null;
}
}
/**
* @return 不区分类型 传什么解析什么
*/
public static T toObj(String jsonStr, Type type) {
T t = null;
try {
t = gson.fromJson(jsonStr, type);
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
/**
* 将Json数组解析成相应的映射对象列表
* 解决类型擦除的问题
*/
public static List toList(String jsonStr, Class clz) {
List list = gson.fromJson(jsonStr, new type(clz));
if (list == null) list = new ArrayList<>();
return list;
}
public static Map toMap(String jsonStr, Class clz) {
Map map = gson.fromJson(jsonStr, new type(clz));
if (map == null) map = new HashMap<>();
return map;
}
public static Map toMap(String jsonStr) {
Map dataMap = new HashMap<>();
try {
Type type = new TypeToken>() {
}.getType();
dataMap = gson.fromJson(jsonStr, type);
} catch (Exception e) {
e.printStackTrace();
}
return dataMap;
}
public static Map toMapStr(String jsonStr) {
Map dataMap = new HashMap<>();
try {
Type type = new TypeToken>() {
}.getType();
dataMap = gson.fromJson(jsonStr, type);
} catch (Exception e) {
e.printStackTrace();
}
return dataMap;
}
private static class type implements ParameterizedType {
private Type type;
private type(Type type) {
this.type = type;
}
@Override
public Type[] getActualTypeArguments() {
return new Type[]{type};
}
@Override
public Type getRawType() {
return ArrayList.class;
}
@Override
public Type getOwnerType() {
return null;
}
}
/**
* 实现了 序列化 接口 对为null的字段进行转换
*/
static class StringConverter implements JsonSerializer, JsonDeserializer {
//字符串为null 转换成"",否则为字符串类型
@Override
public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return json.getAsJsonPrimitive().getAsString();
}
@Override
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
return src == null || src.equals("null") ? new JsonPrimitive("") : new JsonPrimitive(src.toString());
}
}
}
GsonBinder类需要引用 implementation 'com.google.code.gson:gson:2.8.5'
以上就是全部代码了,第一次写文章,文字叙述和表达有不到位的地方,还请见谅,有问题可以留言