ContentProvider insert () всегда выполняется в потоке пользовательского интерфейса?
У меня есть приложение, которое должно получить данные с сервера и вставить их в базу данных SQLite в ответ на ввод пользователя. Я думал, что это будет довольно просто - код, который извлекает данные с сервера, является довольно простым подклассом AsyncTask, и он работает точно так, как я ожидаю, без зависания потока пользовательского интерфейса. Я реализовал функцию обратного вызова для него с помощью простого интерфейса и обернул его в статический класс, поэтому мой код выглядит следующим образом:
MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
@Override
public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
// do something with contents
}
}
Все по-прежнему хорошо. Даже если серверу требуется час для получения данных, пользовательский интерфейс все равно работает без сбоев, поскольку код в getFolderContents выполняется в методе doInBackground объекта AsyncTask (который находится в отдельном потоке от пользовательского интерфейса). В самом конце метода getFolderContents вызывается onFolderContentsResponse и передается список FilesystemEntry, полученный с сервера. Я только действительно говорю все это, так что, надеюсь, ясно, что моя проблема не в методе getFolderContents или в каком-либо из моего сетевого кода, потому что он там никогда не возникает.
Проблема возникает, когда я пытаюсь вставить в базу данных через мой подкласс ContentProvider в методе onFolderContentsResponse; Пользовательский интерфейс всегда зависает во время выполнения этого кода, что заставляет меня поверить, что, несмотря на то, что метод AsIncTask вызывается из метода doInBackground, операции вставки все равно выполняются в потоке пользовательского интерфейса. Вот как выглядит проблемный код:
MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
@Override
public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
insertContentsIntoDB(contents);
}
}
ИinsertContentsIntoDB
метод:
void insertContentsIntoDB(final List<FilesystemEntry> contents) {
for (FilesystemEntry entry : contents) {
ContentValues values = new ContentValues();
values.put(COLUMN_1, entry.attr1);
values.put(COLUMN_2, entry.attr2);
// etc.
mContentResolver.insert(MyContentProvider.CONTENT_URI, values);
}
}
где mContentResolver ранее был установлен как результат метода getContentResolver ().
Я пытался поместить insertContentsIntoDB в отдельную тему, например:
MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
@Override
public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
new Thread(new Runnable() {
@Override
public void run() {
insertContentsIntoDB(contents);
}
}).run();
}
}
Я также попытался запустить каждую отдельную вставку в своем собственном потоке (метод вставки в MyContentProvider синхронизирован, поэтому это не должно вызывать каких-либо проблем):
void insertContentsIntoDB(final List<FilesystemEntry> contents) {
for (FilesystemEntry entry : contents) {
new Thread(new Runnable() {
@Override
public void run() {
ContentValues values = new ContentValues();
values.put(COLUMN_1, entry.attr1);
values.put(COLUMN_2, entry.attr2);
// etc.
mContentResolver.insert(MyContentProvider.CONTENT_URI, values);
}
}).run();
}
}
И просто для хорошей меры я также попробовал оба этих решения с соответствующим кодом в методе doInBackground другого AsyncTask. Наконец, я явно определил MyContentProvider как отдельный процесс в моем AndroidManifest.xml:
<provider android:name=".MyContentProvider" android:process=":remote"/>
Работает нормально, но этоstill seems to run in the UI thread, Это тот момент, когда я действительно начал рвать на себе волосы из-за этого, потому что это не имеет никакого смысла для меня. Независимо от того, что я делаю, пользовательский интерфейс всегда зависает во время вставки. Есть ли способ заставить их не делать этого?