3

当调用片段被暂停/删除时,异步任务会发生什么?我假设任务已完成,但如果有人能证实这一点,那就太好了。我正在尝试解决我的崩溃问题。

我有一个异步任务,它是一个递归图像加载器。图像加载器是它为其加载图像的 listFragment 的内部类。除非我在加载完所有图像之前按下返回按钮,否则图像加载器可以完美运行。当我在所有图像加载完成之前按下后退按钮时,应用程序崩溃。我觉得图像加载器无法访问适配器,但我不确定我是否正确解决了这个问题。我不确定如何在我的异步任务中解决这个问题。如果有人可以帮助我。甚至从我的脑海中蹦出一个想法,让我以不同的方式思考。

任何帮助都是极好的。谢谢你花时间看。

图像加载器

private class ImageLoaderTask extends
        AsyncTask<HashMap<String, Object>, Void, HashMap<String, Object>> {

    @Override
    protected HashMap<String, Object> doInBackground(
            HashMap<String, Object>... hm) {
        InputStream in = null;

        String url = (String) hm[0].get("image");
        int pos = (Integer) hm[0].get("pos");
        url = "http://kzfr.org/u/img/small/" + url;
        URL mUrl;

        try {
            mUrl = new URL(url);
            URLConnection urlConnect = (URLConnection) mUrl
                    .openConnection();
            in = urlConnect.getInputStream();

            File cacheDirectory = getSherlockActivity().getBaseContext()
                    .getCacheDir();

            File tmp = new File(cacheDirectory.getPath() + "/kzfr_small"
                    + pos + ".png");

            FileOutputStream fOut = new FileOutputStream(tmp);

            Bitmap b = BitmapFactory.decodeStream(in);
            b.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();

            HashMap<String, Object> hmBmp = new HashMap<String, Object>();
            hmBmp.put("blank_start", tmp.getPath());
            hmBmp.put("pos", pos);
            return hmBmp;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(HashMap<String, Object> result) {
        // this is the img path that leads to a local image that was just
        // saved on the phone.
        String imgPath = (String) result.get("blank_start");
        // the position of the image in the listview
        int position = (Integer) result.get("pos");
        // local adapter
        SimpleAdapter adapter = (SimpleAdapter) getListAdapter();
        // hashmap entry from the local adapter at the position of the image
        // that we just loaded.
        HashMap<String, Object> hm = (HashMap<String, Object>) adapter
                .getItem(position);
        // replace the actual blank image with the image path that we just
        // loaded
        hm.put("blank_start", imgPath);
        // update listview
        adapter.notifyDataSetChanged();
        // we are done with the current position increment position and move
        // on.
        position++;
        // this while loop finds the next position in the adapter that does
        // not have false for an image path. False indicates that there is
        // no image and i should load a default image.
        while (position < adapter.getCount()) {
            hm = (HashMap<String, Object>) adapter.getItem(position);
            imgPath = (String) hm.get("image");

            if (!imgPath.equalsIgnoreCase("false")) {
                break;
            }
            position++;
        }

        // checks to make sure that the position is not out of bounds on the
        // adapter. If in bounds then there might be more images to load.
        // Start a new ImageLoader. This is a recursive Class.
        if (position < adapter.getCount()) {
            ImageLoaderTask imageLoader = new ImageLoaderTask();

            hm.put("pos", (position));
            imageLoader.execute(hm);
        }

    }

堆栈跟踪

01-14 20:09:28.752: E/AndroidRuntime(6069): FATAL EXCEPTION: main
01-14 20:09:28.752: E/AndroidRuntime(6069): java.lang.NullPointerException
01-14 20:09:28.752: E/AndroidRuntime(6069):     at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:272)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:1)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask.finish(AsyncTask.java:417)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask.access$300(AsyncTask.java:127)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.os.Looper.loop(Looper.java:130)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at android.app.ActivityThread.main(ActivityThread.java:3806)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at java.lang.reflect.Method.invokeNative(Native Method)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at java.lang.reflect.Method.invoke(Method.java:507)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at     com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at   com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-14 20:09:28.752: E/AndroidRuntime(6069):     at dalvik.system.NativeStart.main(Native Method)
4

2 回答 2

4

我认为你在正确的轨道上。

在编写自定义时AsyncTask,许多开发人员忘记了处理任务取消是必要的。简单地取消任务并不意味着它的代码不会在(例如)Activity/Fragment资源上执行,这可能会在当时被释放。这通常在以下步骤中完成:

  1. 创建任务后,保存对它的引用。
  2. Activity/完成后取消所有正在运行的任务Fragment。这通常在Activity.onDestroy()/中完成Fragment.onDestroy()。删除对已取消任务的所有引用。
  3. 在任务代码中:
    1. doInBackground()定期检查它是否isCancelled()。如果是这样,请整理并中止进一步的执行。
    2. 最终处理取消onCancelled()(在 UI 线程上运行)。
    3. 执行取消任务的任何处理onPostExecute()(如果任务被取消,则执行结果)null
于 2013-01-15T04:41:09.493 回答
1

当调用片段被暂停/删除时,异步任务会发生什么?我假设任务已完成,但如果有人能证实这一点,那就太好了。

这是不正确的;该框架不会通过取消您在后台线程中所做的工作来为您完成工作。onPause()像和调用回调的原因onResume()是通知您的应用程序需要清理并取消任何不在长寿命组件中的正在运行的工作,例如Service.

在这种情况下,如果您不取消,任务将继续运行。由于此类被定义为非静态内部类,这也意味着您已经创建了一个临时内存泄漏,因为AsyncTask它持有Fragment对) 甚至可以在onDestroy().

您需要以AsyncTask这样的方式实现您的,它会检查取消标志,您可以手动取消工作onPause()或类似的回调。

于 2013-01-15T04:39:22.557 回答