OkHttp&Retrofit大家都在用,原理很懵懂?2021玩转网络框架
本文是okhttp3.14版本
okhttp框架介绍
同步get请求实现
//这个尽量做成单例,减少创建次数
OkhttpClient okhttpClient;
...
okhttpClient = new OkhttpClient.Builder().build();
...
private void textGet(){
Request request = new Request.Builder()
.url("url")
.build();
//同步请求
new Thread(new Runnable(){
@Override
public void run(){
try{
Response response = okhttpClient.newCall(rrquest).execute();
String result = response.body().string();
runOnUiThread(new Runnable(){
@Override
public void run(){
textView.setText(result);
}
});
}catch(IOException e){
e.printStackTrace();
}
}
}).start();
}
异步body表单post实现
private void textGet(){
FormBody formBody =new FormBody.Builder()
.add("test","这是一个测试的参数")
.build();
//如果服务端支持RequestBody 则也可以:
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),"\"requestBody实体数据\"");
Request request = new Request.Builder()
.url("url")
.post(formBody)
//.post(requestBody )
.build();
//异步请求
okthhpClient.newCall(request).enqueue(new Callback(){
@Override
public void onFailure(Call call,IOException e){
}
@Override
public void onResponse(Call call,Respon respon) throws IOException {
String result = response.body().string();
runOnUiThread(new Runnable(){
@Override
public void run(){
textView.setText(result);
}
});
}
});
}
文件上传实现
记得加入权限,可以导入第三方权限框架
public void upload(String path){
File file = new File(path);
RequestBody body =new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file",file.getName(),MultipartBody.create(MediaType.parse("multipart/form-data"),new File(path)))
.build();
Request request = new Request.Builder()
.url("url")
.post(body)
.build();
//异步请求
okthhpClient.newCall(request).enqueue(new Callback(){
@Override
public void onFailure(Call call,IOException e){
}
@Override
public void onResponse(Call call,Respon respon) throws IOException {
String result = response.body().string();
runOnUiThread(new Runnable(){
@Override
public void run(){
textView.setText(result);
}
});
}
});
}
使用自定义拦截器
public class LogIntercept implement Interceptor{
@Override
public Response intercept(Chain chain) throws IOException{
Request request = chain.request();
//...在这之间插入自己的东西
Log.i("z","intercept:REQUEST="+request.toString());
//...
Response response = chain.proceed(request);
//response.body.toString()//不能这么写,这个是流,直接消费掉了
Log.i("z","intercept:REQUEST="+response.toString());
return response ;
}
}
okhttpClient = new OkhttpClient().Builder()
.addInterceptor(new LogIntercept())
.build();
进入原理分析
okhttp双任务队列机制
从newCall()的enqueue()方法进入,查看异步请求流程
具体实现的由RealCall
拿到dispatcher,然后调用enqueue方法 ,并创建AsyncCall
进入dispatcher的enqueue方法:
分析AsyncCall是什么
AsyncCall就是一个Runnable
回到dispatcher
会把AsyncCall 添加到一个双向队列中去
readyAsyncCalls.add(call);
readyAsyncCalls是一个等待中的队列,所有新进的都加进去
promoteAndExecute();
查看executorService(),线程池方法:
无核心线程,临时工无限多
任务进来直接进临时,创建一个线程去立即执行
线程生存周期只有60s存活
回到AsyncCall execute看执行结束干了什么:
client.dispatcher().finished(this);
亮点所在:
通过结束又来推进当前整个流程;
Volley是靠while循环遍历,while会占用一部分CPU资源
他是靠手动循环的,类似于推进器。
大大减少资源浪费。
责任链模式与拦截器
前一个对象记住下一个对象的引用而连成一条链
实现拦截器的写法
public abstract class Handler{
protate Handler next;//下一个的对象
public Handler getNext(){
return next;
}
public void setNext(Handler next){
this.next = next;
}
public abstrast void hangleRequest(String request);
}
具体拦截处理者
public class MainHandler1 extends Handler{
@Override
public void handleRequest(String request){
//自己的逻辑
if(request.equals("one")){
Log.d("z","具体处理者1处理该请求");
}else{
if(getNext()!= null){
next.handleRequest(request);
}else{
Log.d("z","没有人处理该请求");
}
}
}
}
public class MainHandler2 extends Handler{
@Override
public void handleRequest(String request){
//自己的逻辑
if(request.equals("two")){
Log.d("z","具体处理者2处理该请求");
}else{
if(getNext()!= null){
next.handleRequest(request);
}else{
Log.d("z","没有人处理该请求");
}
}
}
}
public class MainHandler3 extends Handler{
@Override
public void handleRequest(String request){
//自己的逻辑
if(request.equals("three")){
Log.d("z","具体处理者3处理该请求");
}else{
if(getNext()!= null){
next.handleRequest(request);
}else{
Log.d("z","没有人处理该请求");
}
}
}
}
Handler hangler1 = new MainHandler1();
Handler hangler2 = new MainHandler2();
Handler hangler3 = new MainHandler3();
hangler1.setNext(handler2);
hangler2.setNext(handler3);
hangler1.handleRequest("one");//具体处理者1处理该请求
hangler1.handleRequest("three");//具体处理者3处理该请求
TCP三次握手与四次挥手
服务端收到断开时可能有数据没发送完,发送完服务端在发送断开连接。
Socket连接池复用机制
okhttp考虑到三次握手、四次挥手的消耗问题,利用KeepAlive机制,做了优化
默认保持5个存活,5分钟
okhttp小结
双任务队列、
责任链(自定义的在最上面,没往下传就断了)
Retrofit框架介绍
RESTful API
幂等安全:多次操作结果一样
创建请求接口和实例
初始工作:
public interface ApiService{
//定义请求方法
@GET("fc/test")
Call<String > test(@Querty("test") String str); //是retrufit里的call
}
MainActivity
Retrofit retrofit;
OkHttpClient client;
...
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger(){
@Override
public void log(String message){
Log.i("z",message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY);
client = new OkHttpClient.Builder()
.addInterceptor(interceptor)//日志拦截
.build();
retrofit = new Retrofit.Build()
.baseUrl("urlllllll")
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
ApiService apiService =retrofit.create(ApiService.class);
同步GET-POST请求实现
new Thread(new Runnable(){
@Override
public void run(){
try{
Response<String> response = apiService.test("这是一个参数").execute();
Log.d("z","response"+response.body());
}catch(IOException e){
e.printStaceTrace();
}
}
}).start();
异步Post请求实现
apiService.test("这是一个参数").enqueue(new Callback<String>(){
@Override
public void onResponse(Call<String> call,Response<String> response){
Log.d("z","response = "+response.body());
}
@Override
public void onFailure(Call<String> call,Throwable t){
}
});
结果和上面是一样的
post请求该怎么写呢?
public interface ApiService{
//定义请求方法
@GET("fc/test")//GET改为POST即可
Call<String > test(@Querty("test") String str); //是retrufit里的call
....修改为....
@POST("fc/test")
@FormUrlEncoded
Call<String > test(@Field("test") String str);
//加上FormUrlEncoded,Querty改为Field,会把内容放到表单里
@POST("fc/test")
@FormUrlEncoded
Call<String > test(@FieldMap Map<String,String> map);
//这样就放在一个map里<K,V>
//定义一个方法提交一个body
@POST("fc/test2")//不能是get
Call<String> uploadBody(@Body User user);
}
传一个body
public class User{
private String username;
public User(String username){
this.username = username;
}
get()..
set()...
}
apiService.uploadBody(new User("zz")).enqueue(new Callback<String>(){
@Override
public void onResponse(Call<String> call,Response<String> response){
Log.d("z","response = "+response.body());
}
@Override
public void onFailure(Call<String> call,Throwable t){
}
});
上面的ConverterFactory改为Gson
retrofit = new Retrofit.Build()
.baseUrl("urlllllll")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
GsonConverterFactory解析实体类
定义一个数据的具体类型
public class ResponseData{
private String code;
private String msg;
private T data;
getxxx()...
setxxx()...
}
改变接收数据类型:
public interface ApiService{
...
//定义一个方法提交一个body
@POST("fc/test2")
Call<ResponseData<String>> uploadBody(@Body User user);
//String改为ResponseData<String>
}
使用时修改:
apiService.uploadBody(new User("zz")).enqueue(new Callback<ResponseData<String>>(){
@Override
public void onResponse(Call<ResponseData<String>> call,Response<ResponseData<String>> response){
Log.d("z","response = "+response.body().getData());
}
@Override
public void onFailure(Call<ResponseData<String>> call,Throwable t){
}
});
可以指定data类型了,具体还要跟服务端沟通。
使用Retrofit上传文件
//multipart/form-data
public interface ApiService{
...
//multipart/form-data
@Multipart
@Post("fc/upload")
Call<ResponseData<String>> uploadFile(@Part MultipartBody.Part part);
}
MainActivity:
public void shangchuan(String path){
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jp"),file);
MultipartBody.Part part = MultipartBody.Part.createFromData("file",file.getName(),requestBody);
apiService.uploadFile(part).enqueue(new Callback<String>(){
@Override
public void onResponse(Call<String> call,Response<String> response){
Log.d("z","response = "+response.body().getData());
}
@Override
public void onFailure(Call<String> call,Throwable t){
}
});
}
别忘了配置provider..
可以创建一个FileInfo类,把上面Response<String>改为Response<FileInfo>
网络模块用Hilt注入
Hilt---依赖注入--》灵活
RxJava---线程切换
RxJava组合Retrofit使用
强大的为异步而生的框架
别忘了NetWorkModule加上
网络模块完整搭建
封装异常处理
最终
Retrofit原理分析
Retrofit代理模式
从retrofit.create()进入
静态代理及实现
代理持有被代理的引用
被代理类
public class Subject{
public void test(){
System.out.println("被代理对象执行test...");
}
}
代理
public class Proxy{
private Subject subject;
public Proxy(Subject subject){
this.subject=subject;
}
public void test(){
System.out.println("代理对象执行一些不方便的事...");
subject.test();
System.out.println("执行结束...");
}
}
逻辑增强了
如果后很多代理对象,就要有很多代理类。用动态代理解决。
动态代理优势及实现
动态生成的是类的class数据(字节码数据)并加载到jvm中了。
JDK提供了方法
代理的只能是接口
先定义一个接口
public interface UserInterface{
void test();
}
public class UserInterfaceImpl implement UserInterface{
@Override
public void test(){
System.out.println("test.....");
}
}
public class LogHandler implement InvocationHandler{
UserInterfaceImpl impl= new UserInterfaceImpl();
public LogHandler(UserInterfaceImpl impl){
this.impl = impl
}
@Override
public Object invoke(Object proxy,Method method,Object[] args){
//method就是接口中被代理的方法
if(method.getName().equals("test")){
System.out.println("被代理对象执行test之前.....");
Object obj = method.invoke(impl,args);
System.out.println("被代理对象执行test之后.....");
return obj ;
}
return method.invoke(impl,args);//原来的别忘了
}
}
public class JDKProxyTest{
public static void main(String[] args){
//创建代理对象
UserInterfaceImpl Impl= new UserInterfaceImpl();
//获取classLoader
ClassLoader classLoader = impl.getClass().getClassLoader();
//获取接口
Class<?>[] interfaces = impl.getClass().getInterfaces();
//创建InvercationHandler
InvercationHandler handler = new LogHandler(impl);
UserInterface proxy = (UserInterface)Proxy.newProxyInstance(classLoader,interface,handler);
proxy.test();
}
不需要增加新的静态代理类了!!!
JDK动态代理原理
对接口进行处理,拿到相关信息组装成class,加载到内存中,生成字节码对象
ServiceMethod详解
Retrofit小结
Retrofit 搭配Rxjava 、hilt