6

私のアプリケーションでは、ストックカメラアプリを呼び出して写真を撮ります。アクティビティの結果で、写真を処理する asynctask を開始します。(写真を回転してアップロードします)。

また、ギャラリーから写真を削除したいです。これを行うには、asynctask で次のコードを実行します。

// Delete image from gallery
        String[] imageColumns = { MediaStore.Images.Media._ID };
        String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
        String imageWhere = MediaStore.Images.Media._ID + ">?";
        String[] imageArguments = { Integer.toString(captureLastID) };

        CursorLoader imageLoader = new CursorLoader(mActivity);

        imageLoader.setUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        imageLoader.setProjection(imageColumns);
        imageLoader.setSelection(imageWhere);
        imageLoader.setSelectionArgs(imageArguments);
        imageLoader.setSortOrder(imageOrderBy);

        Cursor imageCursor = imageLoader.loadInBackground();

        if (imageCursor.getCount() > 0) {
            while (imageCursor.moveToNext()) {
                int id = imageCursor.getInt(imageCursor
                        .getColumnIndex(MediaStore.Images.Media._ID));

                ContentResolver cr = mActivity.getContentResolver();
                cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        MediaStore.Images.Media._ID + "=?",
                        new String[] { Long.toString(id) });
                break;
            }
        }

        imageCursor.close();

エラーが発生します

Looper.prepare を呼び出していないスレッド内でハンドラを作成することはできません

このエラーの原因と修正方法を教えてください。asynctask が既にバックグラウンドで実行されているときに、loadInBackground を呼び出すという事実と関係がありますか?

これは私のlogcatです:

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:200)
    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    at java.lang.Thread.run(Thread.java:1019)


   Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    at android.os.Handler.<init>(Handler.java:121)
    at android.support.v4.content.Loader$ForceLoadContentObserver.<init>(Loader.java:52)
    at android.support.v4.content.CursorLoader.<init>(CursorLoader.java:96)
    at tasks.ProcessPictureTask.doInBackground(ProcessPictureTask.java:78)
    at tasks.ProcessPictureTask.doInBackground(ProcessPictureTask.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
    ... 4 more
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    at android.os.Handler.<init>(Handler.java:121)
    at android.support.v4.content.Loader$ForceLoadContentObserver.<init>(Loader.java:52)
    at android.support.v4.content.CursorLoader.<init>(CursorLoader.java:96)
    at tasks.ProcessPictureTask.doInBackground(ProcessPictureTask.java:78)
    at tasks.ProcessPictureTask.doInBackground(ProcessPictureTask.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    at java.lang.Thread.run(Thread.java:1019)
4

3 に答える 3

13

実際、受け入れられた答えは正しくありません。これが発生する理由に興味があるようで、アプリの応答性にも役立つ可能性があるため、別の回答をします。

UI を変更していないため、これがクラッシュの原因ではありません。エラーが示すように、バックグラウンド スレッドにルーパーが関連付けられていないことが原因です。ルーパーは、時々メッセージをチェックするメッセージ キューです。たとえば、Handlerを使用するときに使用するものです。

アプリをクラッシュさせる呼び出しの前に次のコード行を追加するだけで、ルーパーを追加できます。

Looper.prepare();

カーソルの読み込み中は UI が応答しないため、UI スレッドではなくバックグラウンド スレッドで重いクエリを実行することには大きな利点があります。応答性が重要な場合は、データベースへの呼び出しをバックグラウンド スレッドで実行する必要があります。

この場合、CursorLoader がルーパーを必要とする理由はまったくありません。少なくとも私が知る限り、例外がスローされるのは不器用な実装です。本当に、LoaderManager を使用すると、CursorLoader の使用がずっと簡単になります

ローダーとバックグラウンド スレッドをいじりたくない場合は、より簡単な方法は、でリスナーを設定しregisterListener(int, OnLoadCompleteListener)、でロードを開始することstartLoading()です。これにより、すべてのスレッドが自動的に処理されるため、コードを節約できる場合があります。

于 2012-10-24T15:51:48.960 に答える
3

MVC パターンをハッキングしています。AsynTask の onBackground メソッドから UI コンポーネントを更新しようとしているため、このエラーが発生しています。UI または初期化を Post または Pre execute メソッドに移動します。のようだ :

 CursorLoader imageLoader = new CursorLoader(mActivity);

に配置する必要がありますprotected void onPreExecute () method.

于 2012-10-24T14:37:41.403 に答える
2

バックグラウンド スレッドで UI 操作を実行しようとしています。これは UI スレッドで実行する必要があります。

于 2012-10-24T14:32:36.427 に答える