37

サーバーからデータをプルし、ユーザー入力に応じてSQLiteデータベースに挿入する必要があるアプリがあります。これは非常に単純だと思いました。サーバーからデータをプルするコードは、AsyncTaskのかなり単純なサブクラスであり、UIスレッドをハングさせることなく期待どおりに機能します。シンプルなインターフェイスでコールバック機能を実装し、静的クラスにラップしたので、コードは次のようになります。

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() {
    @Override
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) {
        // do something with contents
    }
}

すべてまだ良いです。サーバーがデータを取得するのに1時間かかる場合でも、getFolderContentsのコードはAsyncTaskのdoInBackgroundメソッド(UIとは別のスレッドにあります)で実行されているため、UIはスムーズに実行されます。getFolderContentsメソッドの最後で、onFolderContentsResponseが呼び出され、サーバーから受信したFilesystemEntryのリストが渡されます。私が実際に言っているのは、getFolderContentsメソッドやネットワークコードのいずれにも問題が発生していないことを明確にするためです。

この問題は、onFolderContentsResponseメソッド内のContentProviderのサブクラスを介してデータベースに挿入しようとすると発生します。そのコードの実行中は常にUIがハングし、AsyncTaskのdoInBackgroundメソッドから呼び出されたにもかかわらず、挿入はUIスレッドで実行されていると私は信じています。問題のあるコードは次のようになります。

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();
    }
}

また、念のため、別のAsyncTaskのdoInBackgroundメソッドの関連コードを使用してこれらのソリューションの両方を試しました。最後に、MyContentProviderをAndroidManifest.xmlの別のプロセスに存在するものとして明示的に定義しました。

<provider android:name=".MyContentProvider" android:process=":remote"/>

正常に動作しますが、それでもUIスレッドで動作しているようです。それは私が本当にこれで私の髪を引き裂き始めたポイントです、なぜならそれは私には全く意味がないからです。私が何をしても、挿入中は常にUIがハングします。彼らをそうさせない方法はありますか?

4

4 に答える 4

52

を呼び出す代わりに、とそのメソッドmContentResolver.insert()を使用します。非同期クエリを容易にするように設計されています。AsyncQueryHandlerstartInsert()AsyncQueryHandlerContentResolver

于 2012-07-25T08:00:26.830 に答える
3

run元々の問題は、メソッドを呼び出す代わりに、新しいスレッドでメソッドを呼び出していること(これにより、現在のスレッドで実行が続行される)であった可能性がありstartます。これがブライトグレートが彼/彼女の答えで言おうとしていたことだと思います。スレッドの実行と開始の違いを参照してください。よくある間違いです。

于 2014-03-19T17:08:56.913 に答える
0

男。リラックスしてください。そして何でも良く見えるでしょう。最初は、スレッドの開始はFuncrunではなくFuncstartです。新しいスレッドを開始する場合は、funcrunを呼び出すだけではありません。

new Thread(Runnable runnable).start();

次に、Handlerを使用する方がAsyncTaskよりも優れている場合があると思います。

于 2012-07-25T06:52:55.777 に答える
0

AsynTaskdoInBackground(Integer int)のオーバーライドされたメソッドでクエリを実行し、メソッドのメインUIを更新できます。onPostExecute(Integer int)

于 2013-08-21T13:06:37.110 に答える