【长篇】OkHttp&Retrofit

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

okhttp框架介绍

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();
1.png

进入原理分析

okhttp双任务队列机制

3.png

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

4.png

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

进入dispatcher的enqueue方法:

5.png

分析AsyncCall是什么

6.png

AsyncCall就是一个Runnable

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

readyAsyncCalls.add(call);

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

promoteAndExecute();
7.png
8.png

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

9.png

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

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

client.dispatcher().finished(this);
10.png

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

11.png

责任链模式与拦截器

12.png
13.png
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三次握手与四次挥手

15.png

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

Socket连接池复用机制

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

16.png

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

okhttp小结

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

Retrofit框架介绍

17.png

RESTful API

18.png
19.png

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

20.png

创建请求接口和实例

初始工作:

21.png
24.png
22.png
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();
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);
  
}
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();

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){
    
  }
});
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..

29.png

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

网络模块用Hilt注入

30.png

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

31.png
32.png
33.png
34.png

RxJava组合Retrofit使用

强大的为异步而生的框架

35.png
36.png

别忘了NetWorkModule加上

37.png

网络模块完整搭建

封装异常处理

38.png
39.png
40.png
41.png
42.png

最终

43.png

Retrofit原理分析

Retrofit代理模式

从retrofit.create()进入

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

逻辑增强了

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详解

47.png

Retrofit小结

Retrofit 搭配Rxjava 、hilt

你可能感兴趣的:(【长篇】OkHttp&Retrofit)