如何取消运行 BitmapFactory.decodeFile() 的 AsyncTask 并进行清理

发布于 2024-11-02 16:08:20 字数 2323 浏览 7 评论 0原文

在我的界面中,用户从可变数量的歌曲中进行选择,当选择一首歌曲时,我需要显示相关的背景图像。 用户需要在加载图像时保持对界面的控制,并且仍然能够更改歌曲。

我目前执行此操作的方法是使用 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;

绝对-任何建议将不胜感激,我已经搜索了无数关于回收位图、清空、GCing、尝试使用可清除位图的信息。

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.
The user needs to keep control of the interface while the images are loading, and still be able to change song.

The way I currently do this is using an AsyncTask.

I am executing it using:

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

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

attempting to cancel the previous task if it is still running and creating it anew.

The task code does the bitmap loading:

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;
    }

I've made quite a mess of recycling, nulling, running GC, all attempting to cancel the current task so that the newly created one will have enough memory for available for allocation,but whatever I try, I always get outofmemory exceptions when attempting to run too many too soon (about 4/5 times)

The images are 1024x768 jpg files, and ask for 1.5mb memory allocation, i use the bitmapfactory options:

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

Absolutely -any- advice would be appreciated, I've searched to no end about recycling bitmaps, nulling, GCing, attempting to use purgeable bitmaps.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

宁愿没拥抱 2024-11-09 16:08:20

您是否可以尝试使用互斥体序列化调用,以便仅执行一个操作(即使由于某种原因被取消)?请参阅下面的非常基本的方法。显然,您可以在 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]
    }
 }

Can you try to serialize the calls with a Mutex, so that only one operation (even if it is being cancelled for some reason) executes? See a very rudimentary approach below. Obviously you could do more selective locking within the doInBackground method, but you get the picture.

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]
    }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文