【长篇】OkHttp&Retrofit

时间:2021-6-5 作者:qvyue

OkHttp&Retrofit大家都在用,原理很懵懂?2021玩转网络框架
本文是okhttp3.14版本

okhttp框架介绍

【长篇】OkHttp&Retrofit
2.png

同步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&Retrofit
1.png

进入原理分析

okhttp双任务队列机制

【长篇】OkHttp&Retrofit
3.png

从newCall()的enqueue()方法进入,查看异步请求流程
具体实现的由RealCall

【长篇】OkHttp&Retrofit
4.png

拿到dispatcher,然后调用enqueue方法 ,并创建AsyncCall

进入dispatcher的enqueue方法:

【长篇】OkHttp&Retrofit
5.png

分析AsyncCall是什么

【长篇】OkHttp&Retrofit
6.png

AsyncCall就是一个Runnable

回到dispatcher
会把AsyncCall 添加到一个双向队列中去

readyAsyncCalls.add(call);

readyAsyncCalls是一个等待中的队列,所有新进的都加进去

promoteAndExecute();
【长篇】OkHttp&Retrofit
7.png
【长篇】OkHttp&Retrofit
8.png

查看executorService(),线程池方法:

【长篇】OkHttp&Retrofit
9.png

无核心线程,临时工无限多
任务进来直接进临时,创建一个线程去立即执行
线程生存周期只有60s存活

回到AsyncCall execute看执行结束干了什么:

client.dispatcher().finished(this);
【长篇】OkHttp&Retrofit
10.png

亮点所在:
通过结束又来推进当前整个流程;
Volley是靠while循环遍历,while会占用一部分CPU资源
他是靠手动循环的,类似于推进器。
大大减少资源浪费。

【长篇】OkHttp&Retrofit
11.png

责任链模式与拦截器

【长篇】OkHttp&Retrofit
12.png
【长篇】OkHttp&Retrofit
13.png
【长篇】OkHttp&Retrofit
14.png

前一个对象记住下一个对象的引用而连成一条链

实现拦截器的写法

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三次握手与四次挥手

【长篇】OkHttp&Retrofit
15.png

服务端收到断开时可能有数据没发送完,发送完服务端在发送断开连接。

Socket连接池复用机制

okhttp考虑到三次握手、四次挥手的消耗问题,利用KeepAlive机制,做了优化

【长篇】OkHttp&Retrofit
16.png

默认保持5个存活,5分钟

okhttp小结

双任务队列、
责任链(自定义的在最上面,没往下传就断了)

Retrofit框架介绍

【长篇】OkHttp&Retrofit
17.png

RESTful API

【长篇】OkHttp&Retrofit
18.png
【长篇】OkHttp&Retrofit
19.png

幂等安全:多次操作结果一样

【长篇】OkHttp&Retrofit
20.png

创建请求接口和实例

初始工作:

【长篇】OkHttp&Retrofit
21.png
【长篇】OkHttp&Retrofit
24.png
【长篇】OkHttp&Retrofit
22.png
【长篇】OkHttp&Retrofit
23.png
public interface ApiService{
  //定义请求方法
  @GET("fc/test")
  Call 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 response = apiService.test("这是一个参数").execute();

      Log.d("z","response"+response.body());
    }catch(IOException e){
      e.printStaceTrace();
    }
  }
}).start();
【长篇】OkHttp&Retrofit
25.png

异步Post请求实现

apiService.test("这是一个参数").enqueue(new Callback(){
  @Override
  public void onResponse(Call call,Response response){
    Log.d("z","response = "+response.body());
  }
  @Override
  public void onFailure(Call call,Throwable t){
    
  }
});

结果和上面是一样的

post请求该怎么写呢?

public interface ApiService{
  //定义请求方法
  @GET("fc/test")//GET改为POST即可
  Call test(@Querty("test") String str); //是retrufit里的call
  ....修改为....
  @POST("fc/test")
  @FormUrlEncoded
  Call test(@Field("test") String str);
  //加上FormUrlEncoded,Querty改为Field,会把内容放到表单里
  @POST("fc/test")
  @FormUrlEncoded
  Call test(@FieldMap Map map);
  //这样就放在一个map里

  //定义一个方法提交一个body
  @POST("fc/test2")//不能是get
  Call uploadBody(@Body User user);
  
}
【长篇】OkHttp&Retrofit
26.png

传一个body

public class User{
  private String username;
  public User(String username){
    this.username = username;
  }
  get()..
  set()...
}
 apiService.uploadBody(new User("zz")).enqueue(new Callback(){
  @Override
  public void onResponse(Call call,Response response){
    Log.d("z","response = "+response.body());
  }
  @Override
  public void onFailure(Call call,Throwable t){
    
  }
});

上面的ConverterFactory改为Gson

retrofit = new Retrofit.Build()
          .baseUrl("urlllllll")
          .client(client)
          .addConverterFactory(GsonConverterFactory.create())
          .build();

【长篇】OkHttp&Retrofit
27.png

GsonConverterFactory解析实体类

定义一个数据的具体类型

public class ResponseData{
  private String code;
  private String msg;
  private T data;

  getxxx()...
  setxxx()...
}

改变接收数据类型:

public interface ApiService{
  ...
  //定义一个方法提交一个body
  @POST("fc/test2")
  Call> uploadBody(@Body User user);
  //String改为ResponseData
}

使用时修改:

 apiService.uploadBody(new User("zz")).enqueue(new Callback>(){
  @Override
  public void onResponse(Call> call,Response> response){
    Log.d("z","response = "+response.body().getData());
  }
  @Override
  public void onFailure(Call> call,Throwable t){
    
  }
});
【长篇】OkHttp&Retrofit
28.png

可以指定data类型了,具体还要跟服务端沟通。

使用Retrofit上传文件

//multipart/form-data

public interface ApiService{
  ...
  //multipart/form-data
  @Multipart
  @Post("fc/upload")
  Call> 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(){
  @Override
  public void onResponse(Call call,Response response){
    Log.d("z","response = "+response.body().getData());
  }
  @Override
  public void onFailure(Call call,Throwable t){
    
  }
});
  
}

别忘了配置provider..

【长篇】OkHttp&Retrofit
29.png

可以创建一个FileInfo类,把上面Response改为Response

网络模块用Hilt注入

【长篇】OkHttp&Retrofit
30.png

Hilt—依赖注入–》灵活
RxJava—线程切换

【长篇】OkHttp&Retrofit
31.png
【长篇】OkHttp&Retrofit
32.png
【长篇】OkHttp&Retrofit
33.png
【长篇】OkHttp&Retrofit
34.png

RxJava组合Retrofit使用

强大的为异步而生的框架

【长篇】OkHttp&Retrofit
35.png
【长篇】OkHttp&Retrofit
36.png

别忘了NetWorkModule加上

【长篇】OkHttp&Retrofit
37.png

网络模块完整搭建

封装异常处理

【长篇】OkHttp&Retrofit
38.png
【长篇】OkHttp&Retrofit
39.png
【长篇】OkHttp&Retrofit
40.png
【长篇】OkHttp&Retrofit
41.png
【长篇】OkHttp&Retrofit
42.png

最终

【长篇】OkHttp&Retrofit
43.png

Retrofit原理分析

Retrofit代理模式

从retrofit.create()进入

【长篇】OkHttp&Retrofit
44.png
【长篇】OkHttp&Retrofit
45.png

静态代理及实现

代理持有被代理的引用

被代理类

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("执行结束...");
  }
}

逻辑增强了

【长篇】OkHttp&Retrofit
46.png

如果后很多代理对象,就要有很多代理类。用动态代理解决。

动态代理优势及实现

动态生成的是类的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详解

【长篇】OkHttp&Retrofit
47.png

Retrofit小结

Retrofit 搭配Rxjava 、hilt

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。