我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JavaRetrofit源码层深入分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JavaRetrofit源码层深入分析

提醒:看的过程一定要自己点开源码,跟着一步步走,只看容易懵逼

一、自己对Retrofit的理解

Retrofit的中文翻译是改造,改造什么呢?

我认为是对OkHttp的使用、RxJava的使用进行改造。

具体体现在哪里?

在使用OkHttp请求前:

1.用注解统一配置网络请求头和请求参数

2.通过动态代理统一获取注解的请求头和请求参数然后一致组装适配成请求的request,交给okHttp进行请求

使用OkHttp结果返回后:

1.线程切换

线程切换分为两种一种是用Retrofit默认的,另一种是使用RxJava

2.把返回的数据json适配成javabean

简单总结,Retrofit就是为了让OkHttp、RxJava使用的更加简洁的一个封装

二、Retrofit的简单使用

没有添加RxJava

class RetrofitActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //初始化一个Retrofit对象
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .client(OkHttpClientProvider.client()) // 这个OkHttpClientProvider.client()是我自己封装的,就是简单提供一个OkHttpClient
            .build()
        //创建出GitHubApiService这个GitHubApiService的动态代理对象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos 
        val repos = service.listRepos("octocat")
        //调用 enqueue 方法在回调方法里处理结果
        repos.enqueue(object : Callback<List<Repo>?> {
            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                                t.printStackTrace()
            }
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                "response.code() = ${response.code()}".logE()
            }
        })
    }
}
//自己定义的 API 请求接口
interface GitHubApiService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}

三、请求前Retrofit所做的工作

以统一的方式为网络请求准备各种参数

(1).Retrofit的创建,把BaseUrl、OkHttpClient和Gson的实例保存在Retrofit对象中

Retrofit.Builder()的build()方法:

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

首先看这个callFactory,因为我们已经.client(OkHttpClientProvider.client())方法设置了我们的okhttpclient,所以这里callFactory不为null:

    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }
    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

我们没有添加CallbackExecutor(这个看名字就知道是用来处理返回值的),所以这里用的是默认的:

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

记住这个CallbackExecutor,后面会用到

接下来重点看:

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

这个很重要,我们没有调用addCallAdapterFactory方法另外添加AdapterFactory,所以这里第一句的this.adapterFactories是一个空集合,之后调用add方法添加了一个默认的platform.defaultCallAdapterFactory(callbackExecutor),这个很重要需要记住。

接下来把我们的Gson解析器添加到了converterFactories中

最后创建了Retrofit对象,把上面的对象都维护在了Retrofit中,这些都是网络请求需要的工具。

(2).用注解来表示请求头和请求的参数等

如果不知道注解的本质的小伙伴点击传送门:

Java 注解

看一下 注解的具体使用:

    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>

这个就是注解提供的请求方式、请求地址、请求参数等,这个是接口类中的一个方法,后面这个接口类会被动态代理来代理这个接口。

(3).用动态代理来把Retrofit和代理接口的方法上的请求信息,组装成一个OkHttp的请求

如果不知道动态代理本质的小伙伴点击传送门:

Java动态代理与静态代理

使用动态代理,组装请求的代码:

        //创建出GitHubApiService这个GitHubApiService的动态代理对象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos 
        val repos = service.listRepos("octocat")

看Retrofit的create方法:

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
......
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

可以看到就是创建了一个动态代理,动态代理的作用就是代理类的任何一个方法的调用,都会走这个动态代理的invoke方法,即service.listRepos("octocat")的调用会走这个invoke方法。

下面我们具体分析,动态代理的invoke方法如何把各种请求的信息,组装成一个OkHttpCall的:

ServiceMethod<Object, Object> serviceMethod =

(ServiceMethod<Object, Object>) loadServiceMethod(method);

这个ServiceMethod是一个重点,它是真正执行把所有的请求信息,拼成一个Okhttp的请求Call的类:

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这里有一个缓存,serviceMethodCache是一个ConcurrentHashMap来缓存serviceMethod。

然后是ServiceMethod的创建,主要看build方法:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
......
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
......
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
......
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
......
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
......
      return new ServiceMethod<>(this);
    }

可以看出来,这里都在把之前的注解、请求参数、请求地址等解析出来,存到serviceMethod中:

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }

这个ServiceMethod大家现在不用细看它,知道它是解析了我们之前统一用注解格式表示的请求信息,后保存在了自己serviceMethoed的对象中。后面用到的时候,大家自然能体会到。

然后回到动态代理的invoke方法:

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

这个OkHttpCall就是具体发出请求的类,它持有serviceMethod,这里我们先不分析它,继续往下看:

return serviceMethod.callAdapter.adapt(okHttpCall);

这里就和我们调用的地方联系起来了,这个return的是一个okHttp的call:

        //创建出GitHubApiService这个GitHubApiService的动态代理对象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos ⭐⭐⭐注意这里变化了
        val repos = serviceMethod.callAdapter.adapt(okHttpCall)

注意上面service.listRepos("octocat")等于动态代理调用invoke方法的返回值即:

serviceMethod.callAdapter.adapt(okHttpCall)

那我们重点分析:

serviceMethod.callAdapter.adapt(okHttpCall)

首先这个serviceMethod.callAdapter是什么:

callAdapter是在serviceMethod中的build方法中赋值的:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
......
    }
    private CallAdapter<T, R> createCallAdapter() {
......
      try {
        //noinspection unchecked
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
......
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
......
  }

上面是整个callAdapter的调用链,最后是:

adapterFactories.get(i).get(returnType, annotations, this);

这句确定的CallAdapter:

adapterFactoris之前我们提到过要记住的,在Retrofit的build方法中:

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

上面分析了,adapterFactories中只有platform.defaultCallAdapterFactory(callbackExecutor),这一个CallAdapter,adapterFactories.get(i)就是获取platform.defaultCallAdapterFactory(callbackExecutor)的。

接下来看platform.defaultCallAdapterFactory(callbackExecutor)是什么:

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

所以我们得到结论,adapterFactories.get(i)是new ExecutorCallAdapterFactory(callbackExecutor)

注意我们要的是adapterFactories.get(i).get(returnType, annotations, this),所以我们要看ExecutorCallAdapterFactory的get方法:

  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

返回的是:

new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

所以:

serviceMethod.callAdapter是adapterFactories.get(i).get(returnType, annotations, this)是上面这段代码new CallAdapter

那我们要分析的serviceMethod.callAdapter.adapt(okHttpCall),所以我们要的是new CallAdapter的adaptger方法:它返回的是new ExecutorCallbackCall<>(callbackExecutor, call)

这里要注意,这两个参数:

callbackExecutor是我们上面提到过的处理返回值的:

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

call是:

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

好现在我们知道了:

        //创建出GitHubApiService这个GitHubApiService的动态代理对象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos ⭐⭐⭐注意这里变化了
        val repos = serviceMethod.callAdapter.adapt(okHttpCall)

其实是:

        //创建出GitHubApiService这个GitHubApiService的动态代理对象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos ⭐⭐⭐注意这里变化了
        Call repos = new ExecutorCallbackCall<>(callbackExecutor, call)

到这里我们分析了第三小节的题目:如何用动态代理来把Retrofit和代理接口的方法上的请求信息组装成一个OkHttp的请求

(4).发起请求的调用链细节

我们知道发起请求的代码:

        val service = retrofit.create(GitHubApiService::class.java)
        //返回一个Okhttp的请求 Call 对象repos 
        val repos = service.listRepos("octocat")
        //调用 enqueue 方法在回调方法里处理结果
        repos.enqueue(object : Callback<List<Repo>?> {
            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                                t.printStackTrace()
            }
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                "response.code() = ${response.code()}".logE()
            }
        })

这里的repos已经分析了是ExecutorCallbackCall,调用的enqueue方法,接下来我们来看调用链ExecutorCallbackCall的enqueue方法:

    final Executor callbackExecutor;
    final Call<T> delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
 @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }
        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

首先我们已经知道构造方法的两个参数是什么:

delegate 是OkHttpCall

callbackExecutor是platform.defaultCallbackExecutor();

然后我们继续看delegate即OkHttpCall的enqueue方法(上面提到的掠过的OkhttpCall这里用到了):

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    okhttp3.Call call;
    Throwable failure;
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //⭐⭐ 重点
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }
    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }
    if (canceled) {
      call.cancel();
    }
    //⭐⭐ 重点
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //⭐⭐ 重点
        callSuccess(response);
      }
      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

上面我们标记了三个重点:

1.第一个重点call = rawCall = createRawCall();

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

这里用到了上面提到了serviceMethod,之前我们已经总结,它是保存了所有请求需要的信息和请求需要的工具,这里就要使用了:

Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);

就这两句,先把保存的请求头和参数等信息,拼凑成OkHttpClient需要的Request,然后调用serviceMethod.callFactory.newCall(request),这个serviceMethod.callFactory就是我们之前设置的OkHttpClient,调用的它的newCall方法,得到一个OkHttp的Call请求对象,其实是RealCall对象

2.第二个重点call.enqueue(new okhttp3.Callback() {}

这是调用的OkHttpClient的enqueue方法,所以我们之前总结Retrofit就是对OkHttp请求之前和之后的工作的封装,使其有一致、简单、可复用等等。

3.第三个重点callSuccess(response);

     private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

callback.onResponse(OkHttpCall.this, response);,这个callback是之前delegate调用enqueue方法时的参数:

    final Executor callbackExecutor;
    final Call<T> delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
 @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }
        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

注意这个callback是delegate.enqueue方法的参数,不是外层enqueue方法的callback,所以这个回调执行的这个callback的onResponse方法代码:

callbackExecutor.execute(new Runnable() {
  @Override public void run() {
    if (delegate.isCanceled()) {
      // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
    } else {
      callback.onResponse(ExecutorCallbackCall.this, response);
    }
  }
});

callbackExecutor之前提到过是platform.defaultCallbackExecutor():

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

可以看到就是把Runnable来交给handler执行,实现的线程切换

到这里发起请求的调用逻辑分析清楚了。

到此这篇关于Java Retrofit源码层深入分析的文章就介绍到这了,更多相关Java Retrofit内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JavaRetrofit源码层深入分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JavaRetrofit源码层深入分析

这篇文章主要介绍了JavaRetrofit源码层分析,Retrofit是一个RESTful的HTTP网络请求框架的封装,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装
2023-01-13

JavaArrayList深入源码层分析

Java中容器对象主要用来存储其他对象,根据实现原理不同,主要有3类常用的容器对象:ArrayList使用数组结构存储容器中的元素、LinkedList使用链表结构存储容器中的元素
2023-01-17

SpringCloud@RefreshScope注解源码层面深入分析

@RefreshScope注解能帮助我们做局部的参数刷新,但侵入性较强,需要开发阶段提前预知可能的刷新点,并且该注解底层是依赖于cglib进行代理的,所以不要掉入cglib的坑,出现刷了也不更新情况
2023-05-15

SpringAOP源码深入分析

这篇文章主要介绍了SpringAOP源码,AOP(AspectOrientProgramming),直译过来就是面向切面编程,AOP是一种编程思想,是面向对象编程(OOP)的一种补充
2023-01-03

ReactFiber源码深入分析

Fiber可以理解为一个执行单元,每次执行完一个执行单元,ReactFiber就会检查还剩多少时间,如果没有时间则将控制权让出去,然后由浏览器执行渲染操作,这篇文章主要介绍了ReactFiber架构原理剖析,需要的朋友可以参考下
2022-11-13

JavaLinkedHashMap深入分析源码

大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,所以LinkedHashMap就闪亮登场了,这篇文章通过源码解析带你了解LinkedHashMap
2022-11-13

React深入分析useEffect源码

useEffect是react v16.8新引入的特性。我们可以把useEffect hook看作是componentDidMount、componentDidUpdate、componentWillUnmounrt三个函数的组合
2022-11-13

Node.js深入分析Koa源码

本文主要从源码的角度来讲述Koa,尤其是其中间件系统是如何实现的。跟Express相比,Koa的源码异常简洁,Express因为把路由相关的代码嵌入到了主要逻辑中,因此读Express的源码可能长时间不得要领,而直接读Koa的源码几乎没有什么障碍
2022-11-13

【Android】CalledFromWrongThreadException 深入源码分析

先上结论 出现此问题的原因是:在非 UI 线程中创建了 Dialog,而在 UI 线程中调用了 show() 方法 问题还原 在使用 dialog 的时候,因为线程问题,在调用 dismiss() 方法的时候,出现如下常见的 crash–O
2022-06-06

PHP gPRC 源码分析:深入了解 gPRC 的底层原理

这是一篇关于 PHP gPRC 源码分析的,它深入剖析了 gPRC 的底层原理,为你提供对 gRPC 工作原理的深刻见解。
PHP gPRC 源码分析:深入了解 gPRC 的底层原理
2024-02-19

react源码层深入刨析babel解析jsx实现

同作为MVVM框架,React相比于Vue来讲,上手更需要JavaScript功底深厚一些,本系列将阅读React相关源码,从jsx->VDom->RDOM等一些列的过程,将会在本系列中一一讲解
2022-11-13

React深入浅出分析Hooks源码

在react类组件(class)写法中,有setState和生命周期对状态进行管理,但是在函数组件中不存在这些,故引入hooks(版本:>=16.8),使开发者在非class的情况下使用更多react特性
2022-11-13

Vuewatch原理源码层深入讲解

watch是由用户定义的数据监听,当监听的属性发生改变就会触发回调,这项配置在业务中是很常用。在面试时,也是必问知识点,一般会用作和computed进行比较。那么本文就来带大家从源码理解watch的工作流程,以及依赖收集和深度监听的实现
2022-11-13

Android context源码详解及深入分析

Android context详解 前言: Context都没弄明白,还怎么做Android开发? Activity mActivity =new Activity()作为Android开发者,不知道你有没有思考过这个问题,Activity
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录