6

在我的应用程序中,我调用股票相机应用程序来拍照。在我的活动结果中,我启动了一个异步任务来处理照片。(旋转并上传照片)。

我还想从图库中删除照片。为此,我在异步任务中执行以下代码。

// 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 的线程内创建处理程序

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

这是我的日志:

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,因此这不是导致此崩溃的原因。原因是您的后台线程没有与之关联的 Looper,如错误所述。Looper 是一个偶尔检查消息的消息队列。例如,它是您在使用Handler时使用的。

您可以通过在使您的应用程序崩溃的调用之前添加这行代码来简单地添加循环器:

Looper.prepare();

在后台线程而不是 UI 线程上执行繁重的查询有一个很大的优势,因为当光标加载时您的 UI 不会响应。如果响应性对您很重要,则应在后台线程上调用数据库。

现在,在这种情况下,CursorLoader 确实没有理由需要 Looper。至少据我所知,抛出异常只是笨拙的实现。确实,如果您使用LoaderManager和 CursorLoader一起使用会容易得多。

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

于 2012-10-24T15:51:48.960 回答
3

您正在破解 MVC 模式,您收到此错误是因为您尝试从 AsynTask 中的 onBackground 方法更新 UI 组件。将任何 UI 或初始化移动到 Post 或 Pre 执行方法。看起来 :

 CursorLoader imageLoader = new CursorLoader(mActivity);

必须放在protected void onPreExecute () method.

于 2012-10-24T14:37:41.403 回答
2

您正在尝试在后台线程中执行 UI 操作,您应该在 UI 线程中运行它。

于 2012-10-24T14:32:36.427 回答