Android OkHttp + Retrofit 取消请求的方法
更新日期: 2022-8-17
前言
在某一个界面,用户发起了一个网络请求,因为某种原因用户在网络请求完成前离开了当前界面,比较好的做法是取消这个网络请求。
对于OkHttp来说,具体是调用Call
的cancel
方法。
如何找到这一个网络请求并取消掉它呢?
操作大致分为3步。
第一步,在建立请求时,给请求(request)添加标记;
第二步,根据标记,找到请求;
最后,取消这个请求。
OkHttp中的tag
要取消一个请求,OkHttp中可以使用cancel方法,参考 。
OkHttp的request对象有tag。可以根据tag来标示请求。参考Stack Overflow 。
//Set tags for your requests when you build them:
Request request = new Request . Builder ().
url ( url ). tag ( "requestKey" ). build ();
//When you want to cancel:
//A) go through the queued calls and cancel if the tag matches:
for ( Call call : mHttpClient . dispatcher (). queuedCalls ()) {
if ( call . request (). tag (). equals ( "requestKey" ))
call . cancel ();
}
//B) go through the running calls and cancel if the tag matches:
for ( Call call : mHttpClient . dispatcher (). runningCalls ()) {
if ( call . request (). tag (). equals ( "requestKey" ))
call . cancel ();
}
Retrofit中并没有显示地提供取消请求的接口。
2018年时Retrofit仍未提供直接访问call对象的方法
那么如何找到目标网络请求呢?
给每个与页面(Activity,Fragment)相关的request加入自定义header,参考 。
给OkHttpClient添加拦截器。标记出页面的生存状态。如果页面销毁了,则取消对应的request。
以GithubOnAndroid 项目为例,
添加标记
持有一个ConcurrentHashMap来标记页面存活状态。
private static ConcurrentHashMap < String , Boolean > actLiveMap = new ConcurrentHashMap <> (); // 标记Activity是否存活
public static void markPageAlive ( String actName ) {
actLiveMap . put ( actName , true );
}
public static void markPageDestroy ( String actName ) {
actLiveMap . put ( actName , false );
}
Activity中登记界面状态
给当前Activity起名字。每个Activity的标记名必须唯一。
private static final String MY_ACT_NAME = "xxx1Activity" ;
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState );
NetworkCenter . markPageAlive ( MY_ACT_NAME );
// ...
}
@Override
protected void onDestroy () {
super . onDestroy ();
NetworkCenter . markPageDestroy ( MY_ACT_NAME );
// ...
}
OkHttpClient添加拦截器
给OkHttpClient添加拦截器,在拦截器中检查页面的存活情况。
检查后,把这个自定义header移除掉。
public static final String HEADER_ACT_NAME = "Activity-Name" ; // 标记Activity界面名字
private Interceptor lifeInterceptor = new Interceptor () {
@Override
public Response intercept ( Chain chain ) throws IOException {
Request request = chain . request ();
String actName = request . header ( HEADER_ACT_NAME );
if ( ! TextUtils . isEmpty ( actName )) {
Log . d ( TAG , "lifeInterceptor: actName: " + actName );
Boolean actLive = actLiveMap . get ( actName );
if ( actLive == null || ! actLive ) {
chain . call (). cancel ();
Log . d ( TAG , "lifeInterceptor: 取消请求, actName: " + actName );
} else {
Log . d ( TAG , "lifeInterceptor: 发起请求, actName: " + actName );
}
}
Request newRequest = request . newBuilder (). removeHeader ( HEADER_ACT_NAME ). build ();
return chain . proceed ( newRequest );
}
};
OkHttpClient = new OkHttpClient . Builder ()
. readTimeout ( 10 , TimeUnit . SECONDS )
. connectTimeout ( 10 , TimeUnit . SECONDS )
. addInterceptor ( lifeInterceptor ) // 添加拦截器
. build ();
call.cancel()
后,不会再走Retrofit的subscribe方法。
@GET ( "users/{owner}/repos" )
Observable < List < UserRepo >> userRepo (
@Header ( NetworkCenter . HEADER_ACT_NAME ) @Nullable String actName ,
@Path ( "owner" ) String owner ,
@Query ( "sort" ) String sortType );
参考
OkHttp系列
本文也发布在 cnblog
掘金
简书
51CTO
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。欢迎在下方评论~
AndroidTutorial
AndroidTutorial
反馈问题
讨论区
最近更新
投喂作者
Ads