私は、サーバーからデータを取り出し、ユーザーの入力に応じてSQLiteデータベースに挿入する必要のあるアプリケーションを持っています。私はこれがかなりシンプルであると考えました。サーバーからデータを取得するコードは、AsyncTaskのかなり単純なサブクラスであり、UIスレッドを掛けることなく期待通りに機能します。私はシンプルなインターフェイスでコールバック機能を実装し、静的なクラスでラップしたので、私のコードは次のようになります:ContentProvider insert()は常にUIスレッドで実行されますか?
MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
@Override
public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
// do something with contents
}
}
すべてはまだ良いです。サーバーがデータを取得するのに1時間かかる場合でも、getFolderContentsのコードはAsyncTask(UIとは別のスレッドにあります)のdoInBackgroundメソッドで実行されているため、UIはスムーズに実行されます。 getFolderContentsメソッドの最後で、onFolderContentsResponseが呼び出され、サーバーから受信したFilesystemEntryのリストが渡されます。私は本当にすべてのことを言っているだけで、私の問題はgetFolderContentsメソッドやネットワークコードのどこにも存在しないことがうまくいけば明らかです。
問題は、onFolderContentsResponseメソッド内のContentProviderのサブクラスを介してデータベースに挿入しようとすると発生します。 AsyncTaskのdoInBackgroundメソッドから呼び出されているにもかかわらず、挿入が何らかの形でUIスレッド上で実行されていると私は思っています。
MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
@Override
public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
insertContentsIntoDB(contents);
}
}
そしてinsertContentsIntoDB
方法:mContentResolverが以前getContentResolver()メソッドの結果に設定されている
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);
}
}
ここでは、問題のコードは次のようになります。
私はそうのように、独自のスレッドで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でinsertメソッドが同期されるので、このshouldnを実行しようとしました「トンがそこにすべての問題を引き起こす):
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();
}
}
そして、ちょうど良い対策のため、私はまた、別のAsyncTaskのdoInBackgroundメソッドでは、関連するコードでこれらのソリューションの両方を試してみました。最後に、私は明示的に私のAndroidManifest.xmlに別のプロセスに住むようMyContentProviderを定義しました:
<provider android:name=".MyContentProvider" android:process=":remote"/>
それは細かい動作しますが、はまだUIスレッドで実行するようです。それが私にとって本当に意味をなさないので、これは私が本当にこの上に私の髪を引き裂き始めたポイントです。私が何をするにしても、UIは挿入時に常にハングします。それをしないようにする方法はありますか?
仮説を検証するために、ContentProviderから現在のスレッドID /名前を出力します。そして/またはデバッガを使用して、実行中のスレッドをチェックします。 –