"Cannot access database on the main thread" AsyncTask 异常
"Cannot access database on the main thread" Exception in AsyncTask
我用 LiveData 构建了一个简单的 Room 示例,但得到了一个
Cannot access database on the main thread"- IllegalStateException
我的总体架构是 activity 片段,其中包含带 Room 的 ViewModel 和 Repository。
我的调用从这里开始(我剪掉了片段,点击调用该方法的按钮)。
我使用的是androidannotations,但应该与错误无关。
在我看来,它很简单,插入调用显然在 AsyncTask 中,所以这就是我对异常感到困惑的原因。
我的视图模型:
class FragmentAddKeywordsViewModel extends AndroidViewModel {
KeywordsRepository repository;
public FragmentAddKeywordsViewModel(@NonNull Application application) {
super(application);
if (repository == null) {
repository = new KeywordRepository(application);
}
}
public void addKeyword(Keyword keyword) {
repository.addKeyword(keyword);
}
}
这是我的存储库:
public class KeywordsRepository {
private KeywordDao keywordDao;
public KeywordsRepository (Application application) {
KeywordDatabase db = KeywordDatabase.getDatabase(application);
keywordDao= db.keywordDao();
}
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).doInBackground(keyword);
}
private static class insertAsyncTask extends AsyncTask<Keyword, Void, Void> {
private KeywordDao mAsyncTaskDao;
insertAsyncTask(KeywordDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Keyword... params) {
mAsyncTaskDao.insert(params[0]); // This line throws the exception
Log.d(getClass().getSimpleName(), "do in background 1");
return null;
}
}
}
我的数据库
@Database(entities = {Keywords.class}, version = 1, exportSchema = false)
public abstract class KeywordDatabase extends RoomDatabase {
public abstract KeywordsDao keywordDao();
private static KeywordDatabase INSTANCE;
private static RoomDatabase.Callback sRoomDatabaseCallback =
new RoomDatabase.Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
public static KeywordDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (KeywordDatabase .class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
KeywordDatabase.class, "keywords")
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
}
最后但同样重要的是我的道
@Dao
interface KeywordDao {
@Query("SELECT * FROM keywords")
LiveData<List<Keyword>> getAllKeywords();
@Insert
void insert(Keyword keyword);
@Delete
void delete(Keyword keyword);
@Query("DELETE FROM keywords")
void deleteAll();
}
我的错误堆栈到此结束:
java.lang.IllegalStateException: Cannot access database on the main
thread since it may potentially lock the UI for a long period of time.
at
android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:164)
at
android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:211)
at
org.name.project.package.KeywordDao_Impl.insert(KeywordDao_Impl.java:81)
at
org.name.project.package.KeywordsRepository$insertAsyncTask.doInBackground(KeywordsRepository.java:42)
您需要调用 execute
让 asychtask 的 doInBackground
方法 运行 在后台运行
new insertAsyncTask(keywordDao).execute(keyword);
否则用这个
new insertAsyncTask(keywordDao).doInBackground(keyword);
您只是在调用 class 实例的方法。
类似的示例是 java 中的 Thread
,其中 threadInstance.start()
创建的线程不是 threadInstance.run()
改变
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).doInBackground(keyword);
}
到
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).execute(keyword);
}
execute
将在后台线程中调用 doInBackground
。
我用 LiveData 构建了一个简单的 Room 示例,但得到了一个
Cannot access database on the main thread"- IllegalStateException
我的总体架构是 activity 片段,其中包含带 Room 的 ViewModel 和 Repository。
我的调用从这里开始(我剪掉了片段,点击调用该方法的按钮)。
我使用的是androidannotations,但应该与错误无关。
在我看来,它很简单,插入调用显然在 AsyncTask 中,所以这就是我对异常感到困惑的原因。
我的视图模型:
class FragmentAddKeywordsViewModel extends AndroidViewModel {
KeywordsRepository repository;
public FragmentAddKeywordsViewModel(@NonNull Application application) {
super(application);
if (repository == null) {
repository = new KeywordRepository(application);
}
}
public void addKeyword(Keyword keyword) {
repository.addKeyword(keyword);
}
}
这是我的存储库:
public class KeywordsRepository {
private KeywordDao keywordDao;
public KeywordsRepository (Application application) {
KeywordDatabase db = KeywordDatabase.getDatabase(application);
keywordDao= db.keywordDao();
}
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).doInBackground(keyword);
}
private static class insertAsyncTask extends AsyncTask<Keyword, Void, Void> {
private KeywordDao mAsyncTaskDao;
insertAsyncTask(KeywordDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Keyword... params) {
mAsyncTaskDao.insert(params[0]); // This line throws the exception
Log.d(getClass().getSimpleName(), "do in background 1");
return null;
}
}
}
我的数据库
@Database(entities = {Keywords.class}, version = 1, exportSchema = false)
public abstract class KeywordDatabase extends RoomDatabase {
public abstract KeywordsDao keywordDao();
private static KeywordDatabase INSTANCE;
private static RoomDatabase.Callback sRoomDatabaseCallback =
new RoomDatabase.Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
public static KeywordDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (KeywordDatabase .class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
KeywordDatabase.class, "keywords")
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
}
最后但同样重要的是我的道
@Dao
interface KeywordDao {
@Query("SELECT * FROM keywords")
LiveData<List<Keyword>> getAllKeywords();
@Insert
void insert(Keyword keyword);
@Delete
void delete(Keyword keyword);
@Query("DELETE FROM keywords")
void deleteAll();
}
我的错误堆栈到此结束:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:164) at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:211) at org.name.project.package.KeywordDao_Impl.insert(KeywordDao_Impl.java:81) at org.name.project.package.KeywordsRepository$insertAsyncTask.doInBackground(KeywordsRepository.java:42)
您需要调用 execute
让 asychtask 的 doInBackground
方法 运行 在后台运行
new insertAsyncTask(keywordDao).execute(keyword);
否则用这个
new insertAsyncTask(keywordDao).doInBackground(keyword);
您只是在调用 class 实例的方法。
类似的示例是 java 中的 Thread
,其中 threadInstance.start()
创建的线程不是 threadInstance.run()
改变
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).doInBackground(keyword);
}
到
public void addKeyword(Keyword keyword) {
new insertAsyncTask(keywordDao).execute(keyword);
}
execute
将在后台线程中调用 doInBackground
。