问题描述
我正在通过 SyncAdapter onPerformSync 发送几个改造调用,并且我正在尝试通过 try/catch 睡眠语句发送来调节 http 调用.但是,这会阻塞 UI,并且只有在所有调用完成后才会响应.
I m sending several retrofit calls via SyncAdapter onPerformSync and I m trying to regulate http calls by sending out via a try/catch sleep statement. However, this is blocking the UI and will be not responsive only after all calls are done.
在不阻塞 UI 的情况下,在 onPerformSync 后台管理网络调用(使用睡眠定时器)的更好方法是什么?
What is a better way to regulate network calls (with a sleep timer) in background in onPerformSync without blocking UI?
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
String baseUrl = BuildConfig.API_BASE_URL;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(HTTPService.class);
Call<RetroFitModel> RetroFitModelCall = service.getRetroFit(apiKey, sortOrder);
RetroFitModelCall.enqueue(new Callback<RetroFitModel>() {
@Override
public void onResponse(Response<RetroFitModel> response) {
if (!response.isSuccess()) {
} else {
List<RetroFitResult> retrofitResultList = response.body().getResults();
Utility.storeList(getContext(), retrofitResultList);
for (final RetroFitResult result : retrofitResultList) {
RetroFitReview(result.getId(), service);
try {
// Sleep for SLEEP_TIME before running RetroFitReports & RetroFitTime
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
}
RetroFitReports(result.getId(), service);
RetroFitTime(result.getId(), service);
}
}
}
@Override
public void onFailure(Throwable t) {
Log.e(LOG_TAG, "Error: " + t.getMessage());
}
});
}
}
推荐答案
onPerformSync"代码在SyncAdapterThread"线程内执行,而不是在主 UI 线程内执行.然而,当使用回调进行异步调用时,这可能会改变(这是我们这里的情况).
The "onPerformSync" code is executed within the "SyncAdapterThread" thread, not within the Main UI thread. However this could change when making asynchronous calls with callbacks (which is our case here).
这里使用的是异步调用 Retrofitcall.enqueue"方法,这对线程执行有影响.此时我们需要问的问题:
Here you are using an asynchronous call of the Retrofit "call.enqueue" method, and this has an impact on thread execution. The question we need to ask at this point:
回调方法将在哪里执行?
要得到这个问题的答案,我们必须确定发布回调的 Handler 将使用哪个 Looper.
To get the answer to this question, we have to determine which Looper is going to be used by the Handler that will post callbacks.
如果我们自己使用处理程序,我们可以定义循环器、处理程序以及如何在处理程序之间处理消息/可运行对象.但这一次不同,因为我们使用的是第三方框架(Retrofit).所以我们要知道Retrofit使用的是哪个looper?
In case we are playing with handlers ourselves, we can define the looper, the handler and how to process messages/runnables between handlers. But this time it is different because we are using a third party framework (Retrofit). So we have to know which looper used by Retrofit?
请注意,如果 Retrofit 尚未定义他的 Looper,您可能会发现一个异常,说你需要一个活套处理回调.换句话说,异步调用需要在一个循环线程,以便将回调从它被执行的地方.
根据Retrofit的代码源(Platform.java):
According to the code source of Retrofit (Platform.java):
static class Android extends Platform {
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor == null) {
callbackExecutor = new MainThreadExecutor();
}
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
您可以注意到Looper.getMainLooper()",这意味着 Retrofit 会将消息/可运行消息发布到主线程消息队列中(您可以对此进行研究以获得更详细的解释).因此,发布的消息/runnable 将由主线程处理.
You can notice "Looper.getMainLooper()", which means that Retrofit will post messages/runnables into the main thread message queue (you can do research on this for further detailed explanation). Thus the posted message/runnable will be handled by the main thread.
也就是说,onResponse/onFailure 回调将在主线程中执行.它会阻塞 UI,如果你做了太多的工作 (Thread.sleep(SLEEP_TIME);).您可以自行检查:只需在onResponse"回调中设置断点并检查它正在运行的线程.
So that being said, the onResponse/onFailure callbacks will be executed in the main thread. And it's going to block the UI, if you are doing too much work (Thread.sleep(SLEEP_TIME);). You can check it by yourself: just make a breakpoint in "onResponse" callback and check in which thread it is running.
那么如何处理这种情况呢?(关于 Retrofit 使用的问题的答案)
由于我们已经在后台线程 (SyncAdapterThread) 中,因此在您的情况下无需进行异步调用.只需进行 Retrofit 同步调用,然后处理结果,或记录失败.这样,您就不会阻止用户界面.
Since we are already in a background thread (SyncAdapterThread), so there is no need to make asynchronous calls in your case. Just make a Retrofit synchronous call and then process the result, or log a failure. This way, you will not block the UI.
这篇关于在 SyncAdapter onPerformSync 中调节网络调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!