2

在 Activity-A 中,我使用 Surfaceview 和 Bitmap 作为背景。当我去 onPause 时,我释放它并将其设置为 null 并进行显式 GC。它工作正常。但是当我回到同一个Activity时——分配了将近3MB的巨大堆来解码位图。这是因为我在 GC 之后解码位图。

我很擅长回收位图和 GC 过程。但我担心堆分配正在增加以处理相同的位图。

当我移动下一个活动时,我需要将其保存在不应在堆中保留任何空间的地方,当我回来时,我应该去挑选图像。知道如何实现这一目标吗?

以下是现有代码

    @Override
    protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    ourSurfaceView.pause(); 
    Log.i("DragDrop", "In pause drag drop");  
        backGround.release(); 
        optionSelected.release(); 

        backgoundImage.recycle();  

        backgoundImage=null;
        backGround=optionSelected=null;

    if (tts != null) { 
        Log.i("DragDrop", "In pause drag drop stop");
        tts.stop();
        tts.shutdown();
    }  
    System.gc();

} 



    public void run() {
        // TODO Auto-generated method stub
//      Log.i("Notice", "In run of mybringback"); 
        if(backgoundImage == null){ 
            try {
                Log.i("MyBringBack", "In run of mybringback"); 
                backgoundImage = Bitmap.createScaledBitmap(getAssetImage(getApplicationContext(),"backgroundhomepage"), (int) dWidth, (int) dHeight, true);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        ourHolder = getHolder();
        while (isRunning) {
//          Log.i("DragDrop", "ourHolder.getSurface().isValid()" +  ourHolder.getSurface().isValid() );
            if (!ourHolder.getSurface().isValid()){
                continue;
            } 
            canvas = ourHolder.lockCanvas();    
            screenCenterX = dWidth / 2;
            screenCenterY = dHeight / 2; 
            canvas.drawBitmap(backgoundImage, 0, 0, null);   
            if (imagePublishDone) {
                if(!welcomeDone){ 
                    message = "Drop your wish to panda";
                    tts.speak(message, TextToSpeech.QUEUE_FLUSH, null);
                    welcomeDone=true;
                }
                moveImageInEllipticalPath();
            } else {
                initialImagePublish();
            }

            centreReached = false;
            ourHolder.unlockCanvasAndPost(canvas);
        }
    } 


    public  Bitmap getAssetImage(Context context, String filename) throws IOException {
        AssetManager assets = getApplicationContext().getResources().getAssets();
        InputStream buffer = null;
        try {
            buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inTempStorage = new byte[16*1024];   
        options.inPurgeable = true; 
        Bitmap temp = BitmapFactory.decodeStream(buffer, null, options);
        Bitmap finalImage = Bitmap.createScaledBitmap(temp, (int) dWidth, (int) dHeight, true);
        temp.recycle();
        temp=null; 
        return finalImage;
    }
4

1 回答 1

0

我认为对您的问题更好的解决方案是inPurgeable在解码Bitmap.

这样,当系统需要回收内存时,它会在内部“回收”位图,但当需要再次显示位图时,它会自动加载它。

[编辑]

您的代码有几个问题。

  1. inTempStoragegetAssetImage(...)是没用的。这种“优化”应该为解码器提供临时计算所需的内存。如果您不提供它,解码器将简单地自行分配它。如果您将该分配的成本分摊到多个解码中,这只是一种优化。但是,您的解决方案每次都会进行分配。不妨让解码器这样做,因为它会确切知道它需要多少内存。

  2. 似乎您在缩放位图时浪费了很多内存。getAssetImage(...)解码全尺寸图像,然后对其进行缩放、返回和再次缩放。这是很多额外的工作和记忆。您应该考虑通过 对图像进行采样inSampleSize。要找出正确的采样因子,您可以使用inJustDecodeBounds

  3. 最后,您的使用inPurgeable不正确。系统将只能清除使用该选项解码的位图。但是,如上所述,您在加载可清除的位图后继续创建新的位图。此外,即使您修复了您的设计,以便只加载正确的位图,我认为系统无法为您重新加载它,因为您使用decodeStream(...). 流无法以通用方式重新打开和重绕,因此系统将无法重新读取该数据。尝试从文件中解码。您还可以使用inInputShareable来更好地控制清除行为。

于 2013-06-01T19:40:06.533 回答