美文网首页我爱编程
Bitmap的加载和Cache

Bitmap的加载和Cache

作者: 名字_都被占了 | 来源:发表于2018-05-25 23:58 被阅读0次

如何高效地加载Bitmap呢?其实核心思想就是采用BitmapFactory.Options来加载所需尺寸的图片。这里假设通过ImageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这个时候把整个图片加载进来再设给ImageView,这显然是没必要的,因为ImageView并没有办法显示原始的图片。通过BitmapFactory.Options就可以按一定的采样率来加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就会降低内存占用从而在一定程度上避免OOM。

通过BitmapFactory.Options来缩放图片,主要是用到了它的inSampleSize参数,即采样率,当inSampleSize为1时,采样后的图片大小为图片的原始大小,当inSampleSize大于1时,比如为2,那么采样后的图片其宽/高均为原图大小的1/2,而像素数为原图的1/4,其占有的内存大小也为原图的1/4。当inSampleSize小于1时,起作用相当于1,另外inSampleSize的取值应该总是为2的指数,比如1,2,4,8,16...如果外界传递给系统的inSampleSize不为2的指数,那么系统会向下取整并选择一个最接近2的指数来代替。

示例代码如下:

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ceshi);
        imageView=findViewById(R.id.image);
        imageView1=findViewById(R.id.image1);
        imageView.setImageBitmap(getCompressBitmap(getResources(),R.mipmap.touxiang,88,88));
        Log.d("CeShi", "getCompressBitmap(getResources(),R.mipmap.touxiang,88,88).getRowBytes():" + getCompressBitmap(getResources(), R.mipmap.touxiang, 88, 88).getRowBytes());
        Log.d("CeShi", "((BitmapDrawable)imageView1.getDrawable()).getBitmap().getRowBytes():" + ((BitmapDrawable) imageView1.getDrawable()).getBitmap().getRowBytes());
        /*输出结果为:(当然图像也变得不如原来那么清晰了)
        05-25 20:56:11.181 19944-19944/com.example.liang.arlvyou D/CeShi: getCompressBitmap(getResources(),R.mipmap.touxiang,88,88).getRowBytes():812
        05-25 20:56:11.181 19944-19944/com.example.liang.arlvyou D/CeShi: ((BitmapDrawable)imageView1.getDrawable()).getBitmap().getRowBytes():6480*/
    }

    public static Bitmap getCompressBitmap(Resources resources,int resId,int requestWidth,int requestHeight){
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeResource(resources,resId,options);
        options.inSampleSize=getSampleSize(options,requestWidth,requestHeight);
        options.inJustDecodeBounds=false;
        return BitmapFactory.decodeResource(resources,resId,options);
    }

    private static int getSampleSize(BitmapFactory.Options options,int requestWidth,int requestHeight) {
        int sampleSize=1;
        if(options.outWidth>requestWidth||options.outHeight>requestHeight){
            int w=options.outWidth/2;
            int h=options.outHeight/2;
            while ((w/sampleSize)>=requestWidth&&(h/sampleSize)>=requestHeight){
                sampleSize*=2;
            }
        }
        return sampleSize;
    }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layoutAnimation="@anim/viewgroup"
    android:id="@+id/lin">

    <ImageView
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:id="@+id/image"/>
    <ImageView
        android:id="@+id/image1"
        android:src="@mipmap/touxiang"
        android:layout_width="88dp"
        android:layout_height="88dp"/>
</LinearLayout>

LruCache的介绍

在使用LruCache时建议采用support-v4兼容包中提供的LruCache,而不要直接使用Android3.1提供的LruCache。

LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后再添加新的缓存对象。

示例代码如下,下面是加载了本地图片,主要是加载网络图片用

        imageView=findViewById(R.id.image);
        button=findViewById(R.id.button);
        final LruCache<String,Bitmap>lruCache=new LruCache<String,Bitmap>((int) (Runtime.getRuntime().maxMemory()/8)){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes();
            }
        };
        lruCache.put("tupian", BitmapFactory.decodeResource(getResources(),R.mipmap.touxiang));
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                imageView.setImageBitmap(lruCache.get("tupian"));
            }
        });

DiskLruCache的介绍(地址:https://github.com/JakeWharton/DiskLruCache)

DiskLruCache用于实现存储设备缓存,即磁盘缓存,它通过将缓存对象写入文件系统从而实现缓存的效果。

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize);

open方法有四个参数的介绍:

第一个参数表示磁盘缓存在文件系统中的存储路径。如果应用卸载后就希望删除缓存文件,那么就选择SD卡上的缓存目录,如果希望保留缓存数据那就应该选择SD卡上的其他特定目录。
第二个参数表示应用的版本号,一般设为1即可。
第三个参数表示单个节点所对应的数据的个数,一般设为1即可。
第四个参数表示缓存的总大小,比如50MB,写法为1024102450,当缓存大小超出这个设定值后,DiskLruCache会清除一些缓存从而保证总大小不大于这个设定值。

DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。对于一个key来说,如果当前不存在Editor对象,那么edit()就会返回一个新的Editor对象,如果存在Editor对象,就返回对应的Editor对象。如果DiskLruCache的open方法中设置了一个节点只能有一个数据,那么流的参数index就只能为0。最后必须通过Editor的commit()才能提交写入操作。

示例代码如下:

  button = findViewById(R.id.button);
        final File file = new File("/storage/emulated/0/Bytes");
        if (!file.exists()) {
            file.mkdir();
        }
        //本地缓存字符串
        new Thread() {
            @Override
            public void run() {
                final DiskLruCache diskLruCache;
                try {
                    diskLruCache = DiskLruCache.open(file, 1, 1, 50 * 1024 * 1024);
                    DiskLruCache.Editor editor = diskLruCache.edit("diyige");
                    editor.set(0,"hello,world");
                    editor.commit();//记得commit,才能生效
                    button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                Log.d("CeShi", diskLruCache.get("diyige").getString(0));//输出结果为:05-26 21:09:54.733 19153-19153/com.example.liang.arlvyou D/CeShi: hello,world
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        //本地缓存图片的方式如下所示,下面是缓存了字符串,图片也一样
       /* new Thread(){
            @Override
            public void run() {
                try {
                    final DiskLruCache diskLruCache=DiskLruCache.open(file,1,1,50*1024*1024);
                    DiskLruCache.Editor editor=diskLruCache.edit("diyige");
                    final OutputStream outputStream=editor.newOutputStream(0);
                    outputStream.write("woshiliu".getBytes());
                    outputStream.flush();
                    editor.commit();
                    button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                InputStream inputStream=diskLruCache.get("diyige").getInputStream(0);
                                ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
                                int i;
                                while((i=inputStream.read())!=-1){
                                    byteArrayOutputStream.write(i);
                                }
                                s=new String(byteArrayOutputStream.toByteArray());
                                Log.d("CeShi", s);//输出结果为:05-26 21:02:18.913 10685-10685/com.example.liang.arlvyou D/CeShi: woshiliu
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();*/
小技巧:绝大多数情况下,硬件加速都可以解决莫名的卡顿问题,通过设置android:hardwareAccelerated="true"即可为Activity开启硬件加速。

相关文章

  • Bitmap的加载与缓存策略

    Bitmap的加载和Cache Bitmap的高效加载 使用BitmapFactory加载一张图片的方式 deco...

  • 笔记: Bitmap加载和Cache

    Bitmap加载和Cache BitmapOptions decodeFile decodeStream deco...

  • Bitmap的加载和Cache

    如何高效地加载Bitmap呢?其实核心思想就是采用BitmapFactory.Options来加载所需尺寸的图片。...

  • Bitmap 的加载和 Cache

    缓存策略是一个通用的思想,实际开发中经常需要用 Bitmap 做缓存。 12.1 Bitmap 的高效加载 Bit...

  • Bitmap的加载和Cache

    目前比较常用的缓存策略是LruCache(Android3.1提供)和DiskLruCache(是官方文档推荐,但...

  • Bitmap的加载和Cache

    参考资料 Android DiskLruCache完全解析,硬盘缓存的最佳方案 目录 Bitmap的高效加载 An...

  • Bitmap的加载和Cache

    Android开发艺术探索笔记 一:Bitmap的高校加载 Bitmap在Android中指的是一张图片,格式有多...

  • Bitmap的加载和Cache

    由于Bitmap的特殊性以及Android对单个应用所施加的内存限制,比如16M,这导致加载Bitmap的时候很容...

  • Bitmap的加载和Cache

    根据《android开发艺术探索》做的笔记 BitchmapFactory提供了几个加载方法:decodeFile...

  • Bitmap的加载和Cache

    参考资料《Android开发艺术探索》 如何高效的加载一个Bitmap?由于Bitmap的特殊性以及Android...

网友评论

    本文标题:Bitmap的加载和Cache

    本文链接:https://www.haomeiwen.com/subject/cgwujftx.html