【问题标题】:How do I cancel an AsyncTask running BitmapFactory.decodeFile() and clean-up如何取消运行 BitmapFactory.decodeFile() 和清理的 AsyncTask
【发布时间】:2011-04-20 15:17:34
【问题描述】:

In my interface, the user selects from a variable number of songs, and when a song is selected, I need to display the relevant background image. 用户需要在加载图像时保持对界面的控制,并且仍然可以更改歌曲。

我目前这样做的方式是使用 AsyncTask。

我正在使用:

if (LoadBG!=null&&!LoadBG.isCancelled())
LoadBG.cancel(false);

LoadBG = new loadBG();
LoadBG.execute((Object) diff.BGPath);

如果前一个任务仍在运行,则尝试取消它并重新创建它。

任务代码进行位图加载:

protected Boolean doInBackground(Object... param) {

        String pathName = param[0].toString();
        if (!pathName.equals(gfxStore.currentBGPath)) {

            currentBGLoaded = false;
            while(overlayOpacity!=255)
                Thread.yield();
            //set current bg
            if (this.isCancelled())
                return true;
            Bitmap d;
            try
            {
            d = gfxStore.factory.decodeFile(pathName,gfxStore.opts);
            }
            catch (OutOfMemoryError e)
            {
                System.gc();
                return true;
            }
            if (this.isCancelled())
            {
                d.recycle();
                d = null;
                System.gc();
                return true;
            }
            Bitmap s;
            try
            {
            s = gfxStore.scaleImageForCanvas(canvasWidth, canvasHeight,d );
            }
            catch (OutOfMemoryError e)
            {
                //XXX uuuugh
                System.gc();
                return true;
            }
            if (this.isCancelled())
            {
                d.recycle();
                d=null;
                s.recycle();
                s=null;
                System.gc();
                return true;
            }
            d.recycle();
            d=null;
            System.gc();
            gfxStore.currentBG = s;
            gfxStore.currentBGPath = pathName;
            wasChange = true;
        }
        else
            wasChange=false;
        return true;
    }

我把回收、归零、运行 GC 搞得一团糟,所有这些都试图取消当前任务,以便新创建的任务有足够的内存可供分配,但无论我尝试什么,我总是遇到内存不足异常当尝试运行太多太快(大约 4/5 次)时

图像是 1024x768 jpg 文件,并要求 1.5mb 内存分配,我使用 bitmapfactory 选项:

opts.inPreferredConfig = Bitmap.Config.RGB_565;
    opts.inPurgeable = true;
    opts.inSampleSize = 1;

绝对 - 任何建议将不胜感激,我已经搜索了关于回收位图、归零、GC、尝试使用可清除位图的无止境。

【问题讨论】:

标签: android bitmap android-asynctask bitmapfactory


【解决方案1】:

您能否尝试使用 Mutex 序列化调用,以便只执行一个操作(即使它因某种原因被取消)?请参阅下面的一个非常基本的方法。显然,您可以在 doInBackground 方法中进行更多选择性锁定,但您明白了。

static class DecodeLock extends Object {
}
static public DecodeLock lockObject = new DecodeLock();

// ...

protected Boolean doInBackground(Object... param) {
   synchronized (lockObject) {
      String pathName = param[0].toString();
          if (!pathName.equals(gfxStore.currentBGPath)) {

          //[..snip]
    }
 }

【讨论】:

  • 哇,它现在似乎工作正常,没有任何 OOM 错误。只是为了理解这一点,这是否会导致当前任务在下一个开始运行之前完成取消(因为它正在等待同步)?
  • 是的,基本上每个 AsyncTask 都在单独的线程上运行(这是一种简化,但对于我们的目的来说已经足够了)。当一个线程点击“同步”关键字时,它会在“lockObject”上获得一个锁,直到块末尾的匹配大括号。因此,如果另一个线程同时进来,它将阻塞在“同步”行,直到当前线程完成处理(无论是成功处理还是取消)。希望对您有所帮助。
  • +1 表示并发性,我觉得大多数人都可以回顾一下它的重要性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 2014-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多