深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
- 同步请求就是执行请求的操作是阻塞式,直到 HTTP 响应返回。它对应 OKHTTP 中的 execute 方法。
- 异步请求就类似于非阻塞式的请求,它的执行结果一般都是通过接口回调的方式告知调用者。它对应 OKHTTP 中的 enqueue 方法
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(“http://www.test.com”)
.build();
Call call = okHttpClient.newCall(request);
//1.异步请求,通过接口回调告知用户 http 的异步执行结果
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
}
});
//2.同步请求
Response response = call.execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
2、异步请求实现流程
//get的异步请求
public void getAsync(View view) {
//定义okhttp对象
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(“http://www.test.com”).build();
Call call = okHttpClient.newCall(request);
//异步请求:不用创建子线程
//enqueue()并不会阻塞代码的执行,不需要与服务器请求完成之后,才会执行后面的代码
//而且enqueue内部会为我们创建子线程
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.i(“TAG”, "onResponse: " + (Looper.getMainLooper().getThread() == Thread.currentThread()));//为false 表示这是在子线程,需要切换到主线程才能操作UI
if (response.isSuccessful()){
Log.i(TAG,“getAsync:”+response.body().string());
}
}
});
}
call的异步调用是通过RealCall.enqueue()实现的。而请求结果通过Callback回调到主线程
2.1、RealCall.enqueue()
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException(“Already Executed”);
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
将用户创建的callback作为参数传入AsyncCall()构造函数。AsyncCall 继承于Runnable
2.2、AsyncCall
final class AsyncCall extends NamedRunnable {
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
…
/**
- 该方法是在dispather需要执行此请求的时候,分配给它线程池,此异步请求便在这个线程池中执行网络请求。
*/
void executeOn(ExecutorService executorService) {
…
boolean success = false;
try {
//异步的关键:将请求放到线程池中执行。
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
…
success = false;
} finally {
if (!success) {
client.dispatcher().finished(this); // 执行失败会通过Dispatcher进行finished,以后再也不会用此AsyncCall。
}
}
}
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
//请求成功时,回调Response给到用户
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
…
//请求错误时,回调错误接口给到用户
responseCallback.onFailure(RealCall.this, e);
} finally {
//结束一次请求。
client.dispatcher().finished(this);
}
}
}
AsyncCall继承于Runnable,它提供了将Call放到线程池执行的能力,实现了请求的异步流程
2.3、Dispatcher.enqueue()
//准备进行异步调用的请求。
private final Deque readyAsyncCalls = new ArrayDeque<>();
//正在执行的异步请求。
private final Deque runningAsyncCalls = new ArrayDeque<>();
void enqueue(AsyncCall call) {
synchronized (this) {
//将异步请求加入到双端队列中
readyAsyncCalls.add(call);
// 寻找是否有同Host的请求,如果有进行复用
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
//将符合条件的Ready的异步请求转入runningAsyncCalls,并执行
promoteAndExecute();
}
将此请求登记到Dispatcher的预备双端队列中。
以此次的请求的Host来查找可服用的异步请求,如果存在,进行复用。
尝试将刚刚加入预备队的请求执行
2.4、Dipatcher.finish()
private void finished(Deque calls, T call) {
Runnable idleCallback;
synchronized (this) {
…
//一个请求完成后,检查此时是否有在等待执行的请求,并处理。
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
//通知此时已经没有异步请求任务
idleCallback.run();
}
}
- 调度器结束一次请求;
- 当一个异步任务完成后,调度器会触发一次预备任务执行流程。让之前因为最大请求数等限制而不能执行的请求有机会得到执行;
- 通过idleCallback.run()通知此时的调度器空闲状态;
2.5、Dipatcher.promoteAndExecute()
private boolean promoteAndExecute() {
…
List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//检查最大请求数限制和
if (runningAsyncCalls.size() >= maxRequests) break;
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue;
//满足条件,便把预备队的请求提升到执行队列。
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
//将可执行的异步请求放进线程池执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//
asyncCall.executeOn(executorService());
}
return isRunning;
- 该方法是对预备队列里的请求提升至执行队列并执行的一次尝试;
- 如果不能执行,他启动时机将会延后到其他请求结束;
3、同步请求
public static final MediaType JSON
= MediaType.get(“application/json; charset=utf-8”);
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
- 通过Builder模式构建Request;
- 调用client.newCall(),通过request生成一个Call对象。他的实现类是RealCall;
- 随后调用RealCall.execute(),进行同步请求;
3.1、RealCall.execute()
@Override public Response execute() throws IOException {
synchronized (this) {
// 如果该请求已经执行过,报错。
if (executed) throw new IllegalStateException(“Already Executed”);
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
]
[外链图片转存中…(img-g2aTlOk3-1715735030974)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!