How do I cancel an AsyncTask running BitmapFactory.decodeFile() and clean-up

守給你的承諾、 提交于 2020-01-04 06:15:00

问题


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.


回答1:


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


来源:https://stackoverflow.com/questions/5732702/how-do-i-cancel-an-asynctask-running-bitmapfactory-decodefile-and-clean-up

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!