在 SyncAdapter onPerformSync 中调节网络调用
Regulate network calls in SyncAdapter onPerformSync
我正在通过 SyncAdapter onPerformSync 发送几个改造调用,并且我正在尝试通过 try/catch 睡眠语句发送来调节 http 调用。但是,这会阻塞 UI 并且只有在所有调用完成后才会响应。
在不阻塞的情况下,在 onPerformSync 后台调节网络调用(使用睡眠计时器)的更好方法是什么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 主线程中执行。然而,当使用回调进行异步调用时,这可能会改变(我们这里就是这种情况)。
这里使用了Retrofit"call.enqueue"方法的异步调用,这对线程执行有影响。此时我们要问的问题:
Where callback methods are going to be executed?
为了得到这个问题的答案,我们必须确定 Handler 将使用哪个 Looper post 回调。
如果我们自己玩处理程序,我们可以定义循环器、处理程序以及如何在处理程序之间处理 messages/runnables。但是这次不同,因为我们使用的是第三方框架(Retrofit)。所以我们要知道Retrofit用的是哪个looper?
Please note that if Retrofit didn't already define his looper, you
could have caught an exception saying that you need a looper to
process callbacks. In other words, an asynchronous call needs to be in
a looper thread in order to post callbacks back to the thread from
where it was executed.
根据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会postmessages/runnables进入主线程消息队列(这个你可以研究一下,有更详细的解释)。因此 posted message/runnable 将由主线程处理。
也就是说,onResponse/onFailure 回调将在主线程中执行。如果您做的工作太多,它会阻塞 UI (Thread.sleep(SLEEP_TIME);)。可以自己查看:在"onResponse"回调中打个断点,在哪个线程中查看运行.
So how to handle this situation? (the answer to your question about Retrofit use)
由于我们已经在后台线程(SyncAdapterThread)中,所以您的情况不需要进行异步调用。只需进行 Retrofit 同步调用,然后处理结果,或记录失败。 这样,您就不会屏蔽UI。
我正在通过 SyncAdapter onPerformSync 发送几个改造调用,并且我正在尝试通过 try/catch 睡眠语句发送来调节 http 调用。但是,这会阻塞 UI 并且只有在所有调用完成后才会响应。
在不阻塞的情况下,在 onPerformSync 后台调节网络调用(使用睡眠计时器)的更好方法是什么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 主线程中执行。然而,当使用回调进行异步调用时,这可能会改变(我们这里就是这种情况)。
这里使用了Retrofit"call.enqueue"方法的异步调用,这对线程执行有影响。此时我们要问的问题:
Where callback methods are going to be executed?
为了得到这个问题的答案,我们必须确定 Handler 将使用哪个 Looper post 回调。
如果我们自己玩处理程序,我们可以定义循环器、处理程序以及如何在处理程序之间处理 messages/runnables。但是这次不同,因为我们使用的是第三方框架(Retrofit)。所以我们要知道Retrofit用的是哪个looper?
Please note that if Retrofit didn't already define his looper, you could have caught an exception saying that you need a looper to process callbacks. In other words, an asynchronous call needs to be in a looper thread in order to post callbacks back to the thread from where it was executed.
根据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会postmessages/runnables进入主线程消息队列(这个你可以研究一下,有更详细的解释)。因此 posted message/runnable 将由主线程处理。
也就是说,onResponse/onFailure 回调将在主线程中执行。如果您做的工作太多,它会阻塞 UI (Thread.sleep(SLEEP_TIME);)。可以自己查看:在"onResponse"回调中打个断点,在哪个线程中查看运行.
So how to handle this situation? (the answer to your question about Retrofit use)
由于我们已经在后台线程(SyncAdapterThread)中,所以您的情况不需要进行异步调用。只需进行 Retrofit 同步调用,然后处理结果,或记录失败。 这样,您就不会屏蔽UI。