无法在主线程上访问数据库 - Android 房间 - 使用 ThreadPoolExecutor
Cannot access database on the main thread - Android Room - Using ThreadPoolExecutor
我遇到了那个著名的错误 "Cannot access database on the main thread since it may potentially lock the UI for a long periods of time"
但据我了解,我没有在主线程中访问数据库,因为我是在由 ThreadPoolExecutor 执行的 Runnable 中执行调用。我做错了什么?
在下面的方法中,我使用一个runnable 从网络获取数据并将其存储在本地数据库中。
private void refresh() {
executor.execute(() -> {
if (!dataSource.hasData()) {
recipeService.getAllRecipes().enqueue(new Callback<List<Recipe>>() {
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
dataSource.save(response.body());
}
@Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
throw new RuntimeException(t);
}
});
}
});
}
DataSource.save:
@Override
public void save(List<Recipe> recipes) {
for (Recipe recipe : recipes) {
recipeDao.insert(recipe);
int count = 1;
for (Ingredient ingredient : recipe.getIngredients()) {
ingredient.setId(count++);
ingredient.setRecipeId(recipe.getId());
ingredientDao.insert(ingredient);
}
for (Step step : recipe.getSteps()) {
step.setRecipeId(recipe.getId());
stepDao.insert(step);
}
}
}
执行者定义为:
@Provides
Executor executor() {
return new ThreadPoolExecutor(4, 8, 60,
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
}
我遇到的错误:
06-18 03:03:38.653 27231-27231/com.github.alexpfx.udacity.nanodegree.android.baking_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.github.alexpfx.udacity.nanodegree.android.baking_app, PID: 27231
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long periods of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:137)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:184)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.data.local.RecipeDao_Impl.insert(RecipeDao_Impl.java:89)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.recipe.RecipeLocalDataSource.save(RecipeLocalDataSource.java:34)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.recipe.RecipesRepositoryImpl.onResponse(RecipesRepositoryImpl.java:49)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
您的 callback.onresponce() 方法调用似乎来自 UI 线程
像这样更改您的 onResponse 方法会有所帮助
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
dataSource.save(response.body());
}
});
}
您可以将实施更改为:
private void refresh() {
if (!dataSource.hasData()) {
recipeService.getAllRecipes().enqueue(new Callback<List<Recipe>>() {
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
executor.execute(() -> {
dataSource.save(response.body());
});
}
@Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
throw new RuntimeException(t);
}
});
}
}
onResponse 函数总是在 UIThread 中调用。
我遇到了那个著名的错误 "Cannot access database on the main thread since it may potentially lock the UI for a long periods of time"
但据我了解,我没有在主线程中访问数据库,因为我是在由 ThreadPoolExecutor 执行的 Runnable 中执行调用。我做错了什么?
在下面的方法中,我使用一个runnable 从网络获取数据并将其存储在本地数据库中。
private void refresh() {
executor.execute(() -> {
if (!dataSource.hasData()) {
recipeService.getAllRecipes().enqueue(new Callback<List<Recipe>>() {
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
dataSource.save(response.body());
}
@Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
throw new RuntimeException(t);
}
});
}
});
}
DataSource.save:
@Override
public void save(List<Recipe> recipes) {
for (Recipe recipe : recipes) {
recipeDao.insert(recipe);
int count = 1;
for (Ingredient ingredient : recipe.getIngredients()) {
ingredient.setId(count++);
ingredient.setRecipeId(recipe.getId());
ingredientDao.insert(ingredient);
}
for (Step step : recipe.getSteps()) {
step.setRecipeId(recipe.getId());
stepDao.insert(step);
}
}
}
执行者定义为:
@Provides
Executor executor() {
return new ThreadPoolExecutor(4, 8, 60,
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
}
我遇到的错误:
06-18 03:03:38.653 27231-27231/com.github.alexpfx.udacity.nanodegree.android.baking_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.github.alexpfx.udacity.nanodegree.android.baking_app, PID: 27231
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long periods of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:137)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:184)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.data.local.RecipeDao_Impl.insert(RecipeDao_Impl.java:89)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.recipe.RecipeLocalDataSource.save(RecipeLocalDataSource.java:34)
at com.github.alexpfx.udacity.nanodegree.android.baking_app.recipe.RecipesRepositoryImpl.onResponse(RecipesRepositoryImpl.java:49)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
您的 callback.onresponce() 方法调用似乎来自 UI 线程
像这样更改您的 onResponse 方法会有所帮助
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
dataSource.save(response.body());
}
});
}
您可以将实施更改为:
private void refresh() {
if (!dataSource.hasData()) {
recipeService.getAllRecipes().enqueue(new Callback<List<Recipe>>() {
@Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
executor.execute(() -> {
dataSource.save(response.body());
});
}
@Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
throw new RuntimeException(t);
}
});
}
}
onResponse 函数总是在 UIThread 中调用。