如何在Android

时间:2015-09-23 15:45:23

标签: android image performance memory bitmap

我正在尝试创建一个小帮助程序类,可以从多个图像中生成一个图像。它应该采用屏幕的大小,并采取所有图像的相同部分,然后将它们组合成一个单独的图像,并排放一小部分所有图像。

到目前为止,我的班级成功创建了这样的图像。我遇到的唯一问题是在创建此图像后,使用了大量已用RAM。在创建该图像后,您对如何提高RAM使用率有什么建议吗? (我不想耗尽内存)也许我正在以创建图像的方式浪费内存(我打开以获得更好的建议)。 重要的是要知道我无法将这些图像缓存在磁盘上,因为它们永远不会相同。

我注意到的是,一旦我运行手动GC RAM,使用率就会从大约70MiB回到15MiB。

private LruCache<Integer, Bitmap> mMemoryCache;
private List<Integer> IDs = new ArrayList<>();
private CombinerTask task;

private void combineImages(boolean useScreenSize){
        if(task != null)
            task.cancel(true);
        task = new CombinerTask(useScreenSize);
        if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
             task.execute();
        }
    }

class CombinerTask extends AsyncTask<Void,Void,Bitmap>{
    private boolean useScreenSize;

    public CombinerTask(boolean useScreenSize){
        this.useScreenSize = useScreenSize;
    }

    @Override
    protected Bitmap doInBackground(Void...voids) {
        Bitmap bmOverlay;
        if(useScreenSize){
            WindowManager wm = (WindowManager) ImageCombiner.getInstance().getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);

            for(int x = 0; x < IDs.size(); x++){
                float scaleFactor = (float)size.y / (float)mMemoryCache.get(IDs.get(x)).getHeight();
                Bitmap temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)),(int)(mMemoryCache.get(IDs.get(x)).getWidth() * scaleFactor), (int)(mMemoryCache.get(IDs.get(x)).getHeight() * scaleFactor),false);
                mMemoryCache.put(IDs.get(x),temp);
            }

            bmOverlay = Bitmap.createBitmap(size.x,size.y,mMemoryCache.get(IDs.get(0)).getConfig());
        }else {
            bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(),mMemoryCache.get(IDs.get(0)).getHeight(),mMemoryCache.get(IDs.get(0)).getConfig());
        }

        Canvas canvas = new Canvas(bmOverlay);

        for(int i = 0; i < IDs.size(); i++){
            Bitmap bm = Bitmap.createBitmap(mMemoryCache.get(IDs.get(i)),mMemoryCache.get(IDs.get(i)).getWidth()/3,0,bmOverlay.getWidth()/mMemoryCache.size(),mMemoryCache.get(IDs.get(i)).getHeight());
            canvas.drawBitmap(bm,bm.getWidth()*i,0,null);
            bm.recycle();
        }
        canvas = null;
        return bmOverlay;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if(listener != null)
            listener.combineFinished(bitmap);
        for (int i = 0; i < IDs.size(); i++){
            mMemoryCache.get(IDs.get(i)).recycle();
        }
        mMemoryCache = null;
        IDs = null;
    }
}

欢迎任何建议。祝你有美好的一天。

1 个答案:

答案 0 :(得分:0)

我将自己回答这个问题,因为我能够将所需的内存量从70Mib减少到2Mib。我的表现非常简单。而不是在我的代码中升级我的图像,我只采用它的屏幕宽高比。缩放将由ImageView本身完成。这节省了近60%的内存。

此外,我现在在使用后直接回收大部分位图,一旦完成所有工作,LruCache将被驱逐。

这是我的更新代码(这不是最终的,但比以前更好的起点):

private void combineImages(boolean useScreenSize){
    if(task != null)
        task.cancel(true);
    task = new CombinerTask(useScreenSize);
    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } else {
         task.execute();
    }
}

class CombinerTask extends AsyncTask<Void,Void,Bitmap>{
    private boolean useScreenSize;

    public CombinerTask(boolean useScreenSize){
        this.useScreenSize = useScreenSize;
    }
    @Override
    protected Bitmap doInBackground(Void...voids) {
        if(!mMemoryCache.get(IDs.get(0)).isRecycled()) {
            Bitmap bmOverlay;
            if (useScreenSize) {
                WindowManager wm = (WindowManager) ImageCombiner.getInstance().getSystemService(Context.WINDOW_SERVICE);
                Display display = wm.getDefaultDisplay();
                Point size = new Point();
                display.getSize(size);


                for (int x = 0; x < IDs.size(); x++) {
                    int width = mMemoryCache.get(IDs.get(x)).getWidth();
                    int height = mMemoryCache.get(IDs.get(x)).getHeight();

                    float scaleFactorWidth = 1f;
                    float scaleFactorHeight = 1f;
                    scaleFactorWidth = (float) size.x / (float) width;
                    scaleFactorHeight = (float) size.y / (float) height;

                    Bitmap temp = null;
                    if (scaleFactorHeight > scaleFactorWidth) {
                        temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)), (int) (width * scaleFactorHeight), (int) (height * scaleFactorHeight), false);
                        Bitmap cropped = Bitmap.createBitmap(temp, 0, 0, size.x, size.y);
                        temp.recycle();
                        temp = Bitmap.createScaledBitmap(cropped, (int) ((float) cropped.getWidth() / scaleFactorHeight), (int) ((float) cropped.getHeight() / scaleFactorHeight), false);
                        cropped.recycle();

                    } else if (scaleFactorHeight < scaleFactorWidth) {
                        temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)), (int) (width * scaleFactorWidth), (int) (height * scaleFactorWidth), false);
                        Bitmap cropped = Bitmap.createBitmap(temp, 0, 0, size.x, size.y);
                        temp.recycle();
                        temp = Bitmap.createScaledBitmap(cropped, (int) ((float) cropped.getWidth() / scaleFactorWidth), (int) ((float) cropped.getHeight() / scaleFactorWidth), false);
                        cropped.recycle();
                    }
                    if(mMemoryCache.get(IDs.get(x)) != null)
                        mMemoryCache.get(IDs.get(x)).recycle();
                    mMemoryCache.put(IDs.get(x), temp);
                }

                bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(), mMemoryCache.get(IDs.get(0)).getHeight(), mMemoryCache.get(IDs.get(0)).getConfig());
            } else {
                bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(), mMemoryCache.get(IDs.get(0)).getHeight(), mMemoryCache.get(IDs.get(0)).getConfig());
            }

            Canvas canvas = new Canvas(bmOverlay);

            for (int i = 0; i < IDs.size(); i++) {
                Bitmap bm = Bitmap.createBitmap(mMemoryCache.get(IDs.get(i)), 0, 0, bmOverlay.getWidth() / mMemoryCache.size(), mMemoryCache.get(IDs.get(i)).getHeight());
                canvas.drawBitmap(bm, bm.getWidth() * i, 0, null);
                bm.recycle();
            }
            canvas = null;
            return bmOverlay;
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if(listener != null && bitmap != null)
            listener.combineFinished(bitmap);
        for (int i = 0; i < IDs.size(); i++){
            if(mMemoryCache.get(IDs.get(i))!= null)
                mMemoryCache.get(IDs.get(i)).recycle();
        }
        mMemoryCache.evictAll();
        IDs.clear();
    }
}