这里写自定义目录标题
Android 开发之Okhttp 网络请求日志打印
网络请求是开发的日常工作内容之一,网络日志打印也有很多要注意及优化的部分,本文分享我在开发过程中编写的OkHttp网络请求日志打印方法实现
OkHTTP网络日志打印
直接用OKHTTP请求接口的方式
- 要在接口请求的回调方法内进行信息获取和打印 ,即在自定义的Callback实现类或实现对象中
public abstract class MyStringCallBack<T> implements CallBack{
@Override
public void onFailure(Call call, final IOException e) {}
@Override
public void onResponse(Call call, final Response response) throws IOException {}
}
-
当请求流程顺利进行完之后 再onResponse中进行获取网络请求信息和返回的信息打印集合;
因为onResponse和onFailure都有Call对象,并且call能获取到请求信息,所以创建一个方法,用来获取网络请求信息 -
private ArrayList<String> getLogRequstList(Call call) throws IOException { Request request = call.request(); ArrayList<String> logArrays = new ArrayList<>();//声明集合用来保存要打印的log信息 RequestBody requestBody = request.body(); boolean hasRequestBody = requestBody != null;//获取请求的方法,地址 String requestStartMessage = "--> " + request.method() + ' ' + URLDecoder.decode(request.url().toString() ,"UTF-8")+ ' ' ; if ( hasRequestBody) { requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; } logArrays.add(requestStartMessage);//添加到集合中 Headers headers = request.headers(); logArrays.add("---------->REQUEST HEADER<----------"); for (int i = 0, count = headers.size(); i < count; i++) {//header信息 logArrays.add(headers.name(i) + ": " + headers.value(i)); } if (!hasRequestBody) {//是否有body请求参数 logArrays.add("--> END " + request.method()); } else if (bodyEncoded(request.headers())) { logArrays.add("--> END " + request.method() + " (encoded body omitted)"); } else { Buffer buffer = new Buffer(); requestBody.writeTo(buffer); Charset charset = UTF8; MediaType contentType = requestBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } if (isPlaintext(buffer)) { logArrays.add("---------->REQUEST BODY<----------"); //添加请求的body打印信息 logArrays.add(URLDecoder.decode(buffer.readString(charset), "UTF-8")); logArrays.add("--> END " + request.method() + " (" + requestBody.contentLength() + "-byte body)"); } else { logArrays.add("--> END " + request.method() + " (binary " + requestBody.contentLength() + "-byte body omitted)"); } } return logArrays; }
-
再创建一个返回信息打印信息方法
-
/** * * 获取返回的log信息 * @param response * @return * @throws IOException */ private ArrayList<String> getLogResponseList( Response response) throws IOException { String requestTime = response.request().header("requestTime");//为了计算耗时,在请求头中添加了请求时间 long tookMs =System.currentTimeMillis() - (requestTime == null ? 0 : Long.parseLong(requestTime)); ArrayList<String> logArrays = new ArrayList<>();//打印信息集合 ResponseBody responseBody = response.body(); long contentLength = responseBody.contentLength();//此处不用betys()以免response关闭报错 String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; logArrays.add("<-- response code:" + response.code() + " message:" + response.message()+" contentlength:"+bodySize ); logArrays.add("<-- response url:"+URLDecoder.decode(response.request().url().toString(),"UTF-8") ); logArrays.add("<-- costtimes : (" + tookMs + "ms" + ')'); if ( !HttpHeaders.hasBody(response)) { logArrays.add("<-- END HTTP"); } else if (bodyEncoded(response.headers())) { logArrays.add("<-- END HTTP (encoded body omitted)"); } else { BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // Buffer the entire body. Buffer buffer = source.buffer(); Charset charset = UTF8; MediaType contentType = responseBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } if (!isPlaintext(buffer)) { logArrays.add(""); logArrays.add("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)"); return logArrays; } logArrays.add("---------->RESPONSE BODY<----------"); if (contentLength != 0) {//返回的参数 logArrays.add(GsonUtils.retractJson(buffer.clone().readString(charset))); } logArrays.add("<-- END HTTP (" + buffer.size() + "-byte body)"); } return logArrays; }
-
最后创建打印方法,由于网络请求不在同一个线程,为了避免打印的信息错乱,多个请求返回信息输出不对应,我们要用到synchronized关键字来保证线程安全,也就是依次执行。为了保证可读性,还添加了视图框
-
`
`/** * 打印log * @param list */ private synchronized void printLog(ArrayList<String> list,boolean info){ int length = 0 ;//计算每行最长的长度 StringBuilder sb = new StringBuilder(); for(String str : list){ if(str.indexOf("\n")>-1){//有换行的拆分处理 String[] split = str.split("\n"); for(String s : split){ s = s.replace("\t"," ");//缩进替换空格 if(length<s.length()){ length = s.length(); } } }else{ if(length<str.length()){ length = str.length(); } } } length+=14;//左右间距 String head = "HTTP REQUEST START"; sb.append(" \n\n\n"+"\n"); //打印头部 String logHead = "┏"+getEmptyStr((length-head.length())/2,"━")+head+getEmptyStr((length-head.length())/2,"━")+"┓"; sb.append(logHead+"\n"); //打印内容 for(String str : list){ String logStr = ""; if(str.indexOf("\n")>-1){//内部换行替换 splitStr(str,logHead.length(),sb); }else{ if(str.length()> logHead.length()){ outOflength(str,logHead.length(),sb); }else { logStr = "┃ " + str + getEmptyStr((length - 14 - str.length()), " "); //处理中文间距,保证打印无偏差 sb.append(logStr + getEmptyStr((logHead.length() - logStr.length() - 1 - hasCNchar(logStr)), " ") + "┃ \n"); } } } String end = "HTTP REQUEST END"; //打印结尾 sb.append("┗"+getEmptyStr((length-end.length())/2,"━")+end+getEmptyStr((length-end.length())/2,"━")+"┛\n"); sb.append(" \n\n\n"); //Logger.DEFAULT.log(sb.toString());//打印log,避免多个log语句,导致log输出时其他线程的log输出切入此输出阵列内 String[] split = sb.toString().split("\n"); for(String str : split){ if(info) { MyLog.i(TAG, str); }else{ MyLog.e(TAG, str); } } }`
-
接下来看一下打印效果
-
到此 功能就写完了,我把源码放在一个Android开发分享的项目里,项目会陆续上传我自己写的多种工具类及框架,本文相关的 源码地址 http://www.hefan.space:1001/blob/share%2Fandroid.git/master/app%2Fsrc%2Fmain%2Fjava%2Fcom%2Frunt%2Fsharedcode%2Futils%2FPrintLogUtils.java;
-
也可以加QQ群交流技术
最后推荐一个我自己写的MVVM开源项目《Open MVVM》
(加群请进入文章结尾查看群号)
有问题请私信,留言,或者发送邮件到我扣扣邮箱 qingingrunt2010