我为远程API编写了一个TokenManager的RxJava实现(我通过Retrofit
消费)。但是,即使我blockingGet()
subscribeOn(Schedulers.io())
方法调用导致跳过的UI框架的问题。
基本上,我已将getToken()
作为参数包含在API search()
调用方法中。如果该令牌存在,则将提供该令牌,如果不存在,则将通过API token()
调用获取该令牌。 < - 这就是问题所在。当调用此方法时,它会导致UI中跳过的帧(进度条暂时冻结+相应的logcat Choreographer skipped frames!!
消息)
寻找有关如何纠正跳过的帧的建议,或者有关如何更好地实现此代码的建议。
ListFetcher(调用TokenManager
getToken()
的类)
public Single<List<Business>> getList(final String latitude, final String longitude) {
return api
.search(
tokenManager.getToken(), // <-- Here's the TokenManager reference
AppSettings.SEARCH_TERM,
latitude,
longitude,
AppSettings.SEARCH_RADIUS,
Yelp3Api.SEARCH_LIMIT)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(searchResponse -> {
if (searchResponse.getBusinesses().size() < searchResponse.getTotal()) {
return subsequentSearchCalls(searchResponse, latitude, longitude)
.map(businesses -> {
List<Business> list = new ArrayList<>();
list.addAll(searchResponse.getBusinesses());
list.addAll(businesses);
return list;
});
} else {
return Single.just(searchResponse.getBusinesses());
}
});
}
TokenManager getToken()
public synchronized String getToken() {
final String cachedToken = sharedPrefs.getString(tokenKey, "null");
if (cachedToken.equals("null")) {
String tokenString = api
.token(
Yelp3Api.GrantType.CLIENT_CREDENTIALS,
BuildConfig.YELPFUSION_CLIENT_ID,
BuildConfig.YELPFUSION_CLIENT_SECRET)
.subscribeOn(Schedulers.io())
.doOnSuccess(this::setSharedPrefToken)
.map(tokenResponse -> String.format(AUTH_FORMAT, tokenResponse.getAccessToken()))
.blockingGet();
return tokenString;
} else {
return String.format(AUTH_FORMAT, cachedToken);
}
}
Yelp3Api(改造界面)
@FormUrlEncoded
@POST("oauth2/token")
Single<TokenResponse> token(
@Field("grant_type") String grantType,
@Field("client_id") String clientId,
@Field("client_secret") String clientSecret
);
@GET("v3/businesses/search")
Single<SearchResponse> search(
@Header("Authorization") String authorization,
@Query("term") String term,
@Query("latitude") String latitude,
@Query("longitude") String longitude,
@Query("radius") int radius,
@Query("limit") int limit
);
答案 0 :(得分:2)
当你致电getToken()
时,它不会被懒散地执行。它在您的UI线程上执行阻塞调用。
要解决此问题,请将Single.fromCallable
中的getToken和flatMap
上的api.search()
包裹起来
希望这能清除实际发生的事情
答案 1 :(得分:0)
我最后使用okhttp authenticator重新编写此请求以获取身份验证凭据,并使用okhttp interceptor将auth标头添加到传出请求中。
根据the internet,这似乎是一个更好的实施。
但我接受@ Tuby的答案,因为这是对原始问题的更直接的解决方法。