本文連接git
在某一個界面,用戶發起了一個網絡請求,由於某種緣由用戶在網絡請求完成前離開了當前界面,比較好的作法是取消這個網絡請求。對於OkHttp來講,具體是調用Call
的cancel
方法。github
如何找到這一個網絡請求並取消掉它呢?網絡
操做大體分爲3步。第一步,在創建請求時,給請求(request)添加標記;第二步,根據標記,找到請求;最後,取消這個請求。ide
要取消一個請求,OkHttp中能夠使用cancel方法,參考。ui
OkHttp的request對象有tag。能夠根據tag來標示請求。參考Stack Overflow。url
//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對象的方法
那麼如何找到目標網絡請求呢?spa
給每一個與頁面(Activity,Fragment)相關的request加入自定義header,參考。
給OkHttpClient添加攔截器。標記出頁面的生存狀態。若是頁面銷燬了,則取消對應的request。code
以GithubOnAndroid項目爲例,https://github.com/RustFisher/GithubOnAndroid對象
持有一個ConcurrentHashMap<String, Boolean>來標記頁面存活狀態。blog
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的標記名必須惟一。
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添加攔截器,在攔截器中檢查頁面的存活狀況。
檢查後,把這個自定義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);