通过 IntentService 在 Sqlite 数据库中存储内容会阻塞 UI 线程
Storing content in Sqlite database through IntentService blocks the UI thread
我有很多从网络服务中提取的记录,我需要将它们缓存在本地。在执行此操作时(超过 1000 条记录),UI 线程被阻止并且我收到 ANR 警告。我认为为此使用 IntentService 不会阻止 UI。我做错了什么?
几个代码片段:
public class ContentIntentService extends IntentService {
@Override
protected void onHandleIntent(Intent workIntent) {
code = workIntent.getStringExtra("CODE");
getContent(code);
}
private void getContent(final String code) {
if (apiService == null) {
Retrofit client = ApiClient.getClient();
if (client != null)
apiService = client.create(ApiInterface.class);
}
if (apiService == null) {
MobileValetHelper.onConnectionFailed(mAppContext);
return;
}
Call<SectionsResponse> call = apiService.getOutletContent(outletCode, outletCode, MobileValetHelper.getContentSessionToken(mAppContext));
call.enqueue(new Callback<SectionsResponse>() {
@Override
public void onResponse(@NonNull Call<SectionsResponse> call, @NonNull Response<SectionsResponse> response) {
if (response != null
&& response.body() != null
&& response.body().status != null
&& response.body().status.equalsIgnoreCase("Success")
&& response.body().sessionToken != null
&& response.body().data != null
) {
DataCacheHelper dataCacheHelper = new DataCacheHelper(ContentIntentService.this);
dataCacheHelper.insertItems(ContentIntentService.this, items);
}
} else if (response != null
&& response.errorBody() != null) {
Log.e(TAG, "getContent response.errorBody(): " + response.errorBody().string());
}
}
@Override
public void onFailure(@NonNull Call<SectionsResponse> call, @NonNull Throwable t) {
Log.e(TAG, "getContent onFailure: " + t.toString());
}
});
}
}
public class DataCacheHelper {
私有 ContentIntentService mIntentService;
public DataCacheHelper(ContentIntentService service) {
mIntentService = service;
}
public void insertItems(final ArrayList<CategoryItem> items) {
if (mIntentService != null && items != null) {
try {
ContentValues[] valueList = new ContentValues[items.size()];
int i = 0;
ContentValues values;
for (final CategoryItem item : items) {
values = ItemsTable.getContentValues(item);
valueList[i++] = values;
}
context.getContentResolver().bulkInsert(provider.CONTENT_URI, valueList);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
首先,永远不要从 IntentService
做一些异步的事情。一旦onHandleIntent()
returns,IntentService
就会被销毁。在你的情况下,网络 I/O 可能还在继续,更不用说磁盘 I/O.
其次,onResponse()
是在主应用程序线程上调用的,这是您遇到困难的根源。
因此,使用 execute()
而不是 enqueue()
,并直接在用于 onHandleIntent()
.
的线程上的 IntentService
中完成所有工作
我有很多从网络服务中提取的记录,我需要将它们缓存在本地。在执行此操作时(超过 1000 条记录),UI 线程被阻止并且我收到 ANR 警告。我认为为此使用 IntentService 不会阻止 UI。我做错了什么?
几个代码片段:
public class ContentIntentService extends IntentService {
@Override
protected void onHandleIntent(Intent workIntent) {
code = workIntent.getStringExtra("CODE");
getContent(code);
}
private void getContent(final String code) {
if (apiService == null) {
Retrofit client = ApiClient.getClient();
if (client != null)
apiService = client.create(ApiInterface.class);
}
if (apiService == null) {
MobileValetHelper.onConnectionFailed(mAppContext);
return;
}
Call<SectionsResponse> call = apiService.getOutletContent(outletCode, outletCode, MobileValetHelper.getContentSessionToken(mAppContext));
call.enqueue(new Callback<SectionsResponse>() {
@Override
public void onResponse(@NonNull Call<SectionsResponse> call, @NonNull Response<SectionsResponse> response) {
if (response != null
&& response.body() != null
&& response.body().status != null
&& response.body().status.equalsIgnoreCase("Success")
&& response.body().sessionToken != null
&& response.body().data != null
) {
DataCacheHelper dataCacheHelper = new DataCacheHelper(ContentIntentService.this);
dataCacheHelper.insertItems(ContentIntentService.this, items);
}
} else if (response != null
&& response.errorBody() != null) {
Log.e(TAG, "getContent response.errorBody(): " + response.errorBody().string());
}
}
@Override
public void onFailure(@NonNull Call<SectionsResponse> call, @NonNull Throwable t) {
Log.e(TAG, "getContent onFailure: " + t.toString());
}
});
}
}
public class DataCacheHelper { 私有 ContentIntentService mIntentService;
public DataCacheHelper(ContentIntentService service) {
mIntentService = service;
}
public void insertItems(final ArrayList<CategoryItem> items) {
if (mIntentService != null && items != null) {
try {
ContentValues[] valueList = new ContentValues[items.size()];
int i = 0;
ContentValues values;
for (final CategoryItem item : items) {
values = ItemsTable.getContentValues(item);
valueList[i++] = values;
}
context.getContentResolver().bulkInsert(provider.CONTENT_URI, valueList);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
首先,永远不要从 IntentService
做一些异步的事情。一旦onHandleIntent()
returns,IntentService
就会被销毁。在你的情况下,网络 I/O 可能还在继续,更不用说磁盘 I/O.
其次,onResponse()
是在主应用程序线程上调用的,这是您遇到困难的根源。
因此,使用 execute()
而不是 enqueue()
,并直接在用于 onHandleIntent()
.
IntentService
中完成所有工作