Android位图使用优化 [英] Android Bitmap usage Optimization

查看:52
本文介绍了Android位图使用优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究使用位图的不同方式,每种方式各有优缺点.

I've been reading up on different ways to use bitmap each with there own pros and cons.

因此,我有一个问题在我的搜索中并未得到真正回答.我的应用程序中发生大量内存泄漏.因此,我解决了这个问题,并使用了几个位图.特别是一个位图被不同的对象多次使用.我调用位图图像并使用Canvas在其上绘制文本,然后以适合使用该图像的设备的分辨率压缩并保存该图像.

And so I have a question that hasn't really been answered in my search. I have a massive memory leak in my application. So I working through solving the problem, and I use several bitmaps. One Bitmap in particular is used many times by different objects. I call the bitmap image and draw text on it using a Canvas and then compress and save the image in a resolution that suits the device that is using it.

当前,每次需要绘制新文本并创建图像的更新版本时,我都使用BitmapFactory.decodeResource(Resources,ResourceID)获取位图.

Currently I fetch the bitmap using BitmapFactory.decodeResource(Resources, ResourceID) each time I need to draw new text and create a updated version of the image.

是否有更好的方法来获取图像?就像将其缓存在某处:1)可能吗? 2)与从可绘制文件夹中进行解码相比,更好的方法可以多次引用同一张图片?

Is there a better way to fetch the image? Like is caching it somewhere: 1) Possible? 2) A better way to reference the same image many times compared to decoding it from the drawable folder?

注意:此过程是使用AsyncTask完成的,因此根据设备的不同,可以在技术上一次使用映像来一次使用映像.不知道这是否会导致资源冲突.

Note: This process is done using AsyncTask, so depending on the device the image could technically be used accessed serval time all at once. Not sure if that could cause a resource collision.

谢谢,我觉得答案不需要代码,但是如果需要,我可以添加它.

Thanks All, I didn't feel like code was needed for an answer but if it is needed I can add it.

推荐答案

如果您正在寻找Android中用于位图的简单缓存,则以下实现将同时缓存在内存和文件中.再次加载位图资源(由图像文件名标识)时,它将尝试搜索内存,然后在文件高速缓存中查找位图.

If you are looking for simple Caching for Bitmap in Android, The following implementation will cache in both memory and file. when it load it bitmap resource again(identified by image file name), it will try to search the memory and then file cache for the bitmap.

用法:

imageLoader.DisplayImage("image_filename_in_resource_folder",imageView);

imageLoader.DisplayImage("image_filename_in_resource_folder", imageView);

public class ImageLoader {
        final int stub_id = R.drawable.ic_thumbnail;
    private Context mContext;
    MemoryCache memoryCache = new MemoryCache();
    FileCache fileCache;
    ExecutorService executorService;
    private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());

    public ImageLoader(Context context) {
        fileCache = new FileCache(context);
        executorService = Executors.newFixedThreadPool(5);
        this.mContext = context;
    }

    public void DisplayImage(String url, ImageView imageView) {
        imageViews.put(imageView, url);
        Bitmap bitmap = memoryCache.get(url);
        if (bitmap != null)
            imageView.setImageBitmap(bitmap);
        else {
            queuePhoto(url, imageView);
            imageView.setImageResource(stub_id);
        }
    }

    private void queuePhoto(String url, ImageView imageView) {
        PhotoToLoad p = new PhotoToLoad(url, imageView);
        executorService.submit(new PhotosLoader(p));
    }



    //decodes image and scales it to reduce memory consumption
    protected Bitmap decodeFile(File f) {
        try {
            //decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f), null, o);

            //Find the correct scale value. It should be the power of 2.
            final int REQUIRED_SIZE = 150;
            int width_tmp = o.outWidth, height_tmp = o.outHeight;
            int scale = 1;
            while (true) {
                if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
                    break;
                width_tmp /= 2;
                height_tmp /= 2;
                scale *= 2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        } catch (FileNotFoundException e) {
        }
        return null;
    }

    boolean imageViewReused(PhotoToLoad photoToLoad) {
        String tag = imageViews.get(photoToLoad.imageView);
        if (tag == null || !tag.equals(photoToLoad.url))
            return true;
        return false;
    }

    public void clearCache() {
        memoryCache.clear();
        fileCache.clear();
    }

    //Task for the queue
    private class PhotoToLoad {
        public String url;
        public ImageView imageView;

        public PhotoToLoad(String u, ImageView i) {
            url = u;
            imageView = i;
        }
    }

    Bitmap getBitmap(String imageFileName) {
        File f = fileCache.getFile(imageFileName);

        //from SD cache
        Bitmap b = decodeFile(f);
        if (b != null)
            return b;

        try {
            Resources resource = mContext.getResources();
            int imageId = resource.getIdentifier(imageFileName, "drawable", mContext.getPackageName());
            Bitmap bitmap = null;
            InputStream is = resource.openRawResource(imageId);
            OutputStream os = new FileOutputStream(f);
            IOUtils.copy(is, os);
            os.close();
            bitmap = decodeFile(f);
            return bitmap;
        } catch (IOException e) {
            return null;
        }
    }
    class PhotosLoader implements Runnable {
        PhotoToLoad photoToLoad;

        PhotosLoader(PhotoToLoad photoToLoad) {
            this.photoToLoad = photoToLoad;
        }

        public void run() {
            if (imageViewReused(photoToLoad))
                return;
            Bitmap bmp = getBitmap(photoToLoad.url);
            memoryCache.put(photoToLoad.url, bmp);
            if (imageViewReused(photoToLoad))
                return;
            BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
            Activity a = (Activity) photoToLoad.imageView.getContext();
            a.runOnUiThread(bd);
        }
    }

    //Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable {
        Bitmap bitmap;
        PhotoToLoad photoToLoad;

        public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
            bitmap = b;
            photoToLoad = p;
        }

        public void run() {
            if (imageViewReused(photoToLoad))
                return;
            if (null != bitmap) {
                photoToLoad.imageView.setImageBitmap(bitmap);

            }
        }
    }
}

内存缓存类

public class MemoryCache {
    private HashMap<String, SoftReference<Bitmap>> cache = new HashMap<String, SoftReference<Bitmap>>();

    public Bitmap get(String id) {
        if (!cache.containsKey(id))
            return null;
        SoftReference<Bitmap> ref = cache.get(id);
        return ref.get();
    }

    public void put(String id, Bitmap bitmap) {
        cache.put(id, new SoftReference<Bitmap>(bitmap));
    }

    public void clear() {
        cache.clear();
    }
}

文件缓存类

public class FileCache {

    private File cacheDir;

    public FileCache(Context context) {
        //Find the dir to save cached images
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), "LazyList");
        else
            cacheDir = context.getCacheDir();
        if (!cacheDir.exists())
            cacheDir.mkdirs();
    }

    public File getFile(String url) {
        //Identify images by hashcode. Not a perfect solution.
        String filename = String.valueOf(url.hashCode());

        //Another possible solution, using cypto hashing functions like md5
        //String filename = md5(url);
        File f = new File(cacheDir, filename);
        return f;

    }

    public void clear() {
        File[] files = cacheDir.listFiles();
        if (files == null)
            return;
        for (File f : files)
            f.delete();
    }

}

这篇关于Android位图使用优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆