文档章节

Android高效显示图片详解

 等待流星
发布于 2014/04/24 14:05
字数 1147
阅读 461
收藏 16
点赞 0
评论 0

用户在使用ListView或GridView时,控件会自动把用户滑过的已不在当前显示区域的ChildView回收掉,当然也会把该子视图上的bitmap回收掉以释放内存,因此,为了保证一个流畅,快速的操作体验,我们应当避免反复的对同一张图片进行加载,比如说用户在往下看图的过程中又向上滑回去看图,这时对于已经上面已经加载过的图片我们就没有必要让它再加载一遍了,应该能很快的把图片显示出来,这里我们要使用缓存来达到这一目的。


一,使用Memory Cache:

内存缓存速度快,同时为了更加适应实际应用的场景,我们使用LruCache来达到按使用频率缓存的目的,把最近使用的加入缓存,较长时间不用的则会剔除掉释放出空间。

缓存的代码如下:

  1. private LruCache<String, Bitmap> mMemoryCache;  
  2.  
  3. @Override  
  4. protected void onCreate(Bundle savedInstanceState) {  
  5.    ...  
  6.    // Get max available VM memory, exceeding this amount will throw an  
  7.    // OutOfMemory exception. Stored in kilobytes as LruCache takes an  
  8.    // int in its constructor.  
  9.    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
  10.  
  11.    // Use 1/8th of the available memory for this memory cache.  
  12.    final int cacheSize = maxMemory / 8;  
  13.  
  14.    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
  15.        @Override  
  16.        protected int sizeOf(String key, Bitmap bitmap) {  
  17.            // The cache size will be measured in kilobytes rather than  
  18.            // number of items.  
  19.            return bitmap.getByteCount() / 1024;  
  20.        }  
  21.    };  
  22.    ...  
  23. }  
  24.  
  25. public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
  26.    if (getBitmapFromMemCache(key) == null) {  
  27.        mMemoryCache.put(key, bitmap);  
  28.    }  
  29. }  
  30.  
  31. public Bitmap getBitmapFromMemCache(String key) {  
  32.    return mMemoryCache.get(key);  
  33. }  
private LruCache<String, Bitmap> mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get max available VM memory, exceeding this amount will throw an
    // OutOfMemory exception. Stored in kilobytes as LruCache takes an
    // int in its constructor.
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = maxMemory / 8;

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };
    ...
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}


那么我们在loadBitmap的时候就可以先检查下缓存中保存的是否有该图片,有则直接取出使用,不再进行加载。

新的代码如下:

  1. public void loadBitmap(int resId, ImageView imageView) {  
  2.    final String imageKey = String.valueOf(resId);  
  3.  
  4.    final Bitmap bitmap = getBitmapFromMemCache(imageKey);  
  5.    if (bitmap != null) {  
  6.        mImageView.setImageBitmap(bitmap);  
  7.    } else {  
  8.        mImageView.setImageResource(R.drawable.image_placeholder);  
  9.        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);  
  10.        task.execute(resId);  
  11.    }  
  12. }  
public void loadBitmap(int resId, ImageView imageView) {
    final String imageKey = String.valueOf(resId);

    final Bitmap bitmap = getBitmapFromMemCache(imageKey);
    if (bitmap != null) {
        mImageView.setImageBitmap(bitmap);
    } else {
        mImageView.setImageResource(R.drawable.image_placeholder);
        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
        task.execute(resId);
    }
}


当然,我们也要在加载图片是及时的维护缓存,把刚使用到的图片add进缓存中去。

新的代码如下:

  1. class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {  
  2.    ...  
  3.    // Decode image in background.  
  4.    @Override  
  5.    protected Bitmap doInBackground(Integer... params) {  
  6.        final Bitmap bitmap = decodeSampledBitmapFromResource(  
  7.                getResources(), params[0], 100, 100));  
  8.        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);  
  9.        return bitmap;  
  10.    }  
  11.    ...  
  12. }  
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    ...
    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        final Bitmap bitmap = decodeSampledBitmapFromResource(
                getResources(), params[0], 100, 100));
        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
        return bitmap;
    }
    ...
}


在使用内存做缓存的基础上,我们还可以使用Disk控件做为缓存,构成一种二级缓存的结构,设想这种情况,如果App在使用的过程被突然来电打断,那么此时有可能就会引起系统内存的回收,当用户再次切换到App时,App就要进行次很明显的图片再次加载的过程。这个时候,我们就需要用到Disk了,因为足够持久。

下面是是原来的基础上增加使用Disk Cache 的例子:

  1. private DiskLruCache mDiskLruCache;  
  2. private final Object mDiskCacheLock = new Object();  
  3. private boolean mDiskCacheStarting = true;  
  4. private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB  
  5. private static final String DISK_CACHE_SUBDIR = "thumbnails";  
  6.  
  7. @Override  
  8. protected void onCreate(Bundle savedInstanceState) {  
  9.    ...  
  10.    // Initialize memory cache  
  11.    ...  
  12.    // Initialize disk cache on background thread  
  13.    File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);  
  14.    new InitDiskCacheTask().execute(cacheDir);  
  15.    ...  
  16. }  
  17.  
  18. class InitDiskCacheTask extends AsyncTask<File, Void, Void> {  
  19.    @Override  
  20.    protected Void doInBackground(File... params) {  
  21.        synchronized (mDiskCacheLock) {  
  22.            File cacheDir = params[0];  
  23.            mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);  
  24.            mDiskCacheStarting = false; // Finished initialization  
  25.            mDiskCacheLock.notifyAll(); // Wake any waiting threads  
  26.        }  
  27.        return null;  
  28.    }  
  29. }  
  30.  
  31. class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {  
  32.    ...  
  33.    // Decode image in background.  
  34.    @Override  
  35.    protected Bitmap doInBackground(Integer... params) {  
  36.        final String imageKey = String.valueOf(params[0]);  
  37.  
  38.        // Check disk cache in background thread  
  39.        Bitmap bitmap = getBitmapFromDiskCache(imageKey);  
  40.  
  41.        if (bitmap == null) { // Not found in disk cache  
  42.            // Process as normal  
  43.            final Bitmap bitmap = decodeSampledBitmapFromResource(  
  44.                    getResources(), params[0], 100, 100));  
  45.        }  
  46.  
  47.        // Add final bitmap to caches  
  48.        addBitmapToCache(imageKey, bitmap);  
  49.  
  50.        return bitmap;  
  51.    }  
  52.    ...  
  53. }  
  54.  
  55. public void addBitmapToCache(String key, Bitmap bitmap) {  
  56.    // Add to memory cache as before  
  57.    if (getBitmapFromMemCache(key) == null) {  
  58.        mMemoryCache.put(key, bitmap);  
  59.    }  
  60.  
  61.    // Also add to disk cache  
  62.    synchronized (mDiskCacheLock) {  
  63.        if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {  
  64.            mDiskLruCache.put(key, bitmap);  
  65.        }  
  66.    }  
  67. }  
  68.  
  69. public Bitmap getBitmapFromDiskCache(String key) {  
  70.    synchronized (mDiskCacheLock) {  
  71.        // Wait while disk cache is started from background thread  
  72.        while (mDiskCacheStarting) {  
  73.            try {  
  74.                mDiskCacheLock.wait();  
  75.            } catch (InterruptedException e) {}  
  76.        }  
  77.        if (mDiskLruCache != null) {  
  78.            return mDiskLruCache.get(key);  
  79.        }  
  80.    }  
  81.    return null;  
  82. }  
  83.  
  84. // Creates a unique subdirectory of the designated app cache directory. Tries to use external  
  85. // but if not mounted, falls back on internal storage.  
  86. public static File getDiskCacheDir(Context context, String uniqueName) {  
  87.    // Check if media is mounted or storage is built-in, if so, try and use external cache dir  
  88.    // otherwise use internal cache dir  
  89.    final String cachePath =  
  90.            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||  
  91.                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :  
  92.                            context.getCacheDir().getPath();  
  93.  
  94.    return new File(cachePath + File.separator + uniqueName);  
  95. }  

本文转载自:http://blog.csdn.net/zhiying201039/article/details/8682419

共有 人打赏支持
粉丝 5
博文 73
码字总数 10995
作品 0
崇明
[RK3288][Android6.0] 调试笔记 --- 增加操作系统开机时间

Platform: RK3288 OS: Android 6.0 Kernel: 3.10.92 背景: 由于系统有模块需要和外部硬件做同步,因此要延长开机时间。 调试思路: 由于系统只显示了开机动画,没有开机Logo。因此一开始的思...

kris_fei ⋅ 04/17 ⋅ 0

Android 性能优化:手把手教你优化Bitmap图片资源的使用

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的Bitmap 使用优化,希望你们会喜欢 目录 1. 优化原因 即 为什么要优化图片资源,具体如下图:

Carson_Ho ⋅ 04/24 ⋅ 0

AndroidManifest.xml详解

我们在进行APP开发的时候都会遇到一个文件:AndroidManifest.xml。从刚开始进行Android开发,到现在已经过去了几个月,还是对这个文件一知半解,只知道它是配置用的。但是这文件里的东西具体...

闪电的蓝熊猫 ⋅ 05/14 ⋅ 0

0-2岁的app开发人员必读,Android开发APP前的准备事项

随着移动互联网的兴起,各行各业对移动应用的需求越来越大,从事APP开发的人也越来越多,APP开发行业可以说是方兴未艾。APP开发是比较复杂的事情,涉及产品、美工设计、服务器端开发、Andro...

传授知识的天使 ⋅ 06/06 ⋅ 0

android开发常用工具类、高仿客户端、附近厕所、验证码助手、相机图片处理等源码

Android精选源码 android开发过程经常要用的工具类源码(http://www.apkbus.com/thread-599826-1-1.html) Android类似QQ空间个人主页下拉头部放大的布局效果(http://www.apkbus.com/thread-5...

逆鳞龙 ⋅ 05/29 ⋅ 0

Android:手把手教你学会使用Google出品的序列化神器Protocol Buffer

前言 习惯用 数据存储格式的你们,相信大多都没听过 其实 是 出品的一种轻量 & 高效的结构化数据存储格式,性能比 真的强!太!多! 由于 出品,我相信已经具备足够的吸引力 今天,我将详细介...

Carson_Ho ⋅ 04/16 ⋅ 0

Android HWUI硬件加速模块浅析

原址 什么是硬件加速(What) 传统软件的UI绘制是依靠CPU来完成的,硬件加速就是将绘制任务交由GPU来执行。Android系统负责硬件加速的模块主要是HWUI,如下图所示: 为什么要硬件加速(Why)...

u010164190 ⋅ 04/27 ⋅ 0

Matrix, ColorMatrix

作为Android源码中的一个常用类,它的作用是持有一个3*3的矩阵数组,用于坐标的转换。 Matrix用来制作动画效果、改变图片大小、给图片加各类滤镜等。 Matrix 的应用 - 压缩图像;Matrix 的应...

shareus ⋅ 04/13 ⋅ 0

Android性能优化:这是一份详细的布局优化 指南(含、、)

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的布局优化,希望你们会喜欢。 目录 /** 实例说明:在上述例子,在布局B中 通过标签引用布局C 此时:布局层级为 = RelativeLa...

Carson_Ho ⋅ 05/14 ⋅ 0

Android性能优化:手把手教你如何让App更快、更稳、更省(含内存、布局优化等)

前言 在 开发中,性能优化策略十分重要 因为其决定了应用程序的开发质量:可用性、流畅性、稳定性等,是提高用户留存率的关键 本文全面讲解性能优化中的所有知识,献上一份 性能优化的详细攻...

Carson_Ho ⋅ 05/30 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Sqoop

1.Sqoop: 《=》 SQL to Hadoop 背景 1)场景:数据在RDBMS中,我们如何使用Hive或者Hadoop来进行数据分析呢? 1) RDBMS ==> Hadoop(广义) 2) Hadoop ==> RDBMS 2)原来可以通过MapReduce I...

GordonNemo ⋅ 10分钟前 ⋅ 0

全量构建和增量构建的区别

1.全量构建每次更新时都需要更新整个数据集,增量构建只对需要更新的时间范围进行更新,所以计算量会较小。 2.全量构建查询时不需要合并不同Segment,增量构建查询时需要合并不同Segment的结...

无精疯 ⋅ 20分钟前 ⋅ 0

如何将S/4HANA系统存储的图片文件用Java程序保存到本地

我在S/4HANA的事务码MM02里为Material维护图片文件作为附件: 通过如下简单的ABAP代码即可将图片文件的二进制内容读取出来: REPORT zgos_api.DATA ls_appl_object TYPE gos_s_obj.DA...

JerryWang_SAP ⋅ 38分钟前 ⋅ 0

云计算的选择悖论如何对待?

导读 人们都希望在工作和生活中有所选择。但心理学家的调查研究表明,在多种选项中进行选择并不一定会使人们更快乐,甚至不会产生更好的决策。心理学家Barry Schwartz称之为“选择悖论”。云...

问题终结者 ⋅ 46分钟前 ⋅ 0

637. Average of Levels in Binary Tree - LeetCode

Question 637. Average of Levels in Binary Tree Solution 思路:定义一个map,层数作为key,value保存每层的元素个数和所有元素的和,遍历这个树,把map里面填值,遍历结束后,再遍历这个map,把每...

yysue ⋅ 今天 ⋅ 0

IDEA配置和使用

版本控制 svn IDEA版本控制工具不能使用 VCS-->Enable Version Control Integration File-->Settings-->Plugins 搜索Subversion,勾选SVN和Git插件 删除.idea文件夹重新生成项目 安装SVN客户......

bithup ⋅ 今天 ⋅ 0

PE格式第三讲扩展,VA,RVA,FA的概念

作者:IBinary 出处:http://www.cnblogs.com/iBinary/ 版权所有,欢迎保留原文链接进行转载:) 一丶VA概念 VA (virtual Address) 虚拟地址的意思 ,比如随便打开一个PE,找下它的虚拟地址 这边...

simpower ⋅ 今天 ⋅ 0

180623-SpringBoot之logback配置文件

SpringBoot配置logback 项目的日志配置属于比较常见的case了,之前接触和使用的都是Spring结合xml的方式,引入几个依赖,然后写个 logback.xml 配置文件即可,那么在SpringBoot中可以怎么做?...

小灰灰Blog ⋅ 今天 ⋅ 0

冒泡排序

原理:比较两个相邻的元素,将值大的元素交换至右端。 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第...

人觉非常君 ⋅ 今天 ⋅ 0

Vagrant setup

安装软件 brew cask install virtualboxbrew cask install vagrant 创建project mkdir -p mst/vmcd mst/vmvagrant init hashicorp/precise64vagrant up hashicorp/precise64是一个box......

遥借东风 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部