在调用一个耗时较长的接口时,我们往往需要显示一个加载框,以便让用户知道我们的 APP 正在工作而不是卡死。
一般的做法,是这样实现:
showLoading(); // 在请求开始之前显示加载框
http.async('/api/...')
...
.setOnComplete(state -> {
// 在请求结束(成功|失败|异常)之后关闭加载框
hideLoading();
})
.post();
这样当然可以解决问题,但是一个应用开发下来至少涉及到有三四十个接口请求,多的甚至到成百上千个,如果每个加载框的逻辑都这么写,会造成很多冗余代码,很不优雅。
那可不可以,在请求接口时,我们只给一个标签,如果有这个标签,请求时就自动显示加载框,结束后就自动关闭加载框呢?像这样:
http.async('/api/...')
.tag("LOADING") // 自动显示和关闭加载框
...
.post();
当然可以!OkHttps 扩展机制的强大,一不小心又体现了。来,我们直接看实现代码!
预处理器是在网络请求开始之前执行,我们可以再这里显示加载框:
HTTP http = HTTP.builder()
... // 省略其它配置项
.addPreprocessor(chain -> {
HttpTask<?> task = chain.getTask();
// 根据标签判断是否显示加载框
if (task.isTagged("LOADING")) {
showLoading(context(task)); // 显示加载框
}
chain.proceed();
})
... // 省略其它配置项
.build();
其中第9行使用了一个context(HttpTask<?> task)
方法,它的作用是从HttpTask
的绑定对象中取得一个Context
对象,用于创建加载框。
HTTP http = HTTP.builder()
... // 省略其它配置项
.completeListener((HttpTask<?> task, HttpResult.State state) -> {
if (task.isTagged("LOADING")) {
hideLoading(); // 关闭加载框
}
return true;
});
... // 省略其它配置项
.build();