asynctask中的CursorLoader,无法在未调用Looper.prepare的线程内创建处理程序

Rob*_*met 4 android android-asynctask

在我的应用程序中,我打电话给相机应用程序拍照.在我的活动结果中,我启动了一个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();
Run Code Online (Sandbox Code Playgroud)

我收到了错误

无法在未调用Looper.prepare的线程内创建处理程序

是什么导致此错误,我该如何解决?它是否与我调用loadInBackground这一事实有关,而asynctask已经在后台运行了?

这是我的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)
Run Code Online (Sandbox Code Playgroud)

pgs*_*rom 11

实际上,接受的答案是不正确的.您似乎对发生这种情况的原因感兴趣,它也可能有助于您的应用程序的响应性,所以我会给出另一个答案:

您没有改变UI,因此这不是导致崩溃的原因.原因是您的后台线程没有与之关联的Looper,因为错误说明了.looper是偶尔检查消息的消息队列.例如,它是您在使用Handler时使用的.

只需在崩溃应用程序的调用之前添加以下代码行即可添加looper:

Looper.prepare();
Run Code Online (Sandbox Code Playgroud)

在后台线程而不是在UI线程上执行大量查询有一个很大的优势,因为在加载游标时,UI不会响应.如果响应对您很重要,则应在后台线程上调用db.

现在,在这种情况下,CursorLoader确实没有理由需要looper.就我所知,至少只是笨拙的实现,抛出异常.实际上,如果你使用LoaderManager,使用CursorLoader会更容易.

如果你不想搞乱加载器和后台线程,那么更简单的方法是设置一个监听器registerListener(int, OnLoadCompleteListener)并开始加载startLoading().这会自动为您处理所有线程,并可能为您节省一些代码.