Как отменить AsyncTask с запущенным BitmapFactory.decodeFile () и очистить - PullRequest
2 голосов
/ 20 апреля 2011

В моем интерфейсе пользователь выбирает из переменного числа песен, и когда песня выбрана, мне нужно отобразить соответствующее фоновое изображение. Пользователь должен контролировать интерфейс во время загрузки изображений и при этом иметь возможность изменять песню.

В настоящее время я использую 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,5 Мб, я использую опции bitmapfactory:

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

Буду признателен за абсолютно любые советы, я без конца искал информацию об утилизации растровых изображений, обнулении, GCing, попытке использовать очищаемые растровые изображения.

1 Ответ

4 голосов
/ 20 апреля 2011

Можете ли вы попробовать сериализовать вызовы с помощью 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]
    }
 }
...