hbasebitmap如何存储
1. 如何高效使用和管理Bitmap
一、图片加载流程
首先,我们谈谈加载图片的流程,项目中的该模块处理流程如下:
1.在UI主线程中,从内存缓存中获取图片,找到后返回。找不到进入下一步;
2.在工作线程中,从磁盘缓存中获取图片,找到即返回并更新内存缓存。找不到进入下一步;
3.在工作线程中,从网络中获取图片,找到即返回并同时更新内存缓存和磁盘缓存。找不到显示默认以提示。
二、内存缓存类(PanoMemCache)
这里使用Android提供的LruCache类,该类保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。当cache已满的时候加入新的item时,在队列尾部的item会被回收。
[java] view plain print ?
public class PanoMemoryCache {
// LinkedHashMap初始容量
private static final int INITIAL_CAPACITY = 16;
// LinkedHashMap加载因子
private static final int LOAD_FACTOR = 0.75f;
// LinkedHashMap排序模式
private static final boolean ACCESS_ORDER = true;
// 软引用缓存
private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
// 硬引用缓存
private static LruCache<String, Bitmap> mLruCache;
public PanoMemoryCache() {
// 获取单个进程可用内存的最大值
// 方式一:使用ActivityManager服务(计量单位为M)
/*int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();*/
// 方式二:使用Runtime类(计量单位为Byte)
final int memClass = (int) Runtime.getRuntime().maxMemory();
// 设置为可用内存的1/4(按Byte计算)
final int cacheSize = memClass / 4;
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
if(value != null) {
// 计算存储bitmap所占用的字节数
return value.getRowBytes() * value.getHeight();
} else {
return 0;
}
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
if(oldValue != null) {
// 当硬引用缓存容量已满时,会使用LRU算法将最近没有被使用的图片转入软引用缓存
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
}
}
};
/*
* 第一个参数:初始容量(默认16)
* 第二个参数:加载因子(默认0.75)
* 第三个参数:排序模式(true:按访问次数排序;false:按插入顺序排序)
*/
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(INITIAL_CAPACITY, LOAD_FACTOR, ACCESS_ORDER) {
private static final long serialVersionUID = 7237325113220820312L;
@Override
protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {
if(size() > SOFT_CACHE_SIZE) {
return true;
}
return false;
}
};
}
/**
* 从缓存中获取Bitmap
* @param url
* @return bitmap
*/
public Bitmap getBitmapFromMem(String url) {
Bitmap bitmap = null;
// 先从硬引用缓存中获取
synchronized (mLruCache) {
bitmap = mLruCache.get(url);
if(bitmap != null) {
// 找到该Bitmap之后,将其移到LinkedHashMap的最前面,保证它在LRU算法中将被最后删除。
mLruCache.remove(url);
mLruCache.put(url, bitmap);
return bitmap;
}
}
// 再从软引用缓存中获取
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);
if(bitmapReference != null) {
bitmap = bitmapReference.get();
if(bitmap != null) {
// 找到该Bitmap之后,将它移到硬引用缓存。并从软引用缓存中删除。
mLruCache.put(url, bitmap);
mSoftCache.remove(url);
return bitmap;
} else {
mSoftCache.remove(url);
}
}
}
return null;
}
/**
* 添加Bitmap到内存缓存
* @param url
* @param bitmap
*/
public void addBitmapToCache(String url, Bitmap bitmap) {
if(bitmap != null) {
synchronized (mLruCache) {
mLruCache.put(url, bitmap);
}
}
}
/**
* 清理软引用缓存
*/
public void clearCache() {
mSoftCache.clear();
mSoftCache = null;
}
}
补充一点,由于4.0平台以后对SoftReference类引用的对象调整了回收策略,所以该类中的软引用缓存实际上没什么效果,可以去掉。2.3以前平台建议保留。
三、磁盘缓存类(PanoDiskCache)
五、使用decodeByteArray()还是decodeStream()?
讲到这里,有童鞋可能会问我为什么使用BitmapFactory.decodeByteArray(data, 0, data.length, opts)来创建Bitmap,而非使用BitmapFactory.decodeStream(is, null, opts)。你这样做不是要多写一个静态方法readInputStream()吗?
没错,decodeStream()确实是该使用情景下的首选方法,但是在有些情形下,它会导致图片资源不能即时获取,或者说图片被它偷偷地缓存起来,交 还给我们的时间有点长。但是延迟性是致命的,我们等不起。所以在这里选用decodeByteArray()获取,它直接从字节数组中获取,贴近于底层 IO、脱离平台限制、使用起来风险更小。
六、引入缓存机制后获取图片的方法
[java] view plain print ?
/**
* 加载Bitmap
* @param url
* @return
*/
private Bitmap loadBitmap(String url) {
// 从内存缓存中获取,推荐在主UI线程中进行
Bitmap bitmap = memCache.getBitmapFromMem(url);
if(bitmap == null) {
// 从文件缓存中获取,推荐在工作线程中进行
bitmap = diskCache.getBitmapFromDisk(url);
if(bitmap == null) {
// 从网络上获取,不用推荐了吧,地球人都知道~_~
bitmap = PanoUtils.downloadBitmap(this, url);
if(bitmap != null) {
diskCache.addBitmapToCache(bitmap, url);
memCache.addBitmapToCache(url, bitmap);
}
} else {
memCache.addBitmapToCache(url, bitmap);
}
}
return bitmap;
}
七、工作线程池化
有关多线程的切换问题以及在UI线程中执行loadBitmap()方法无效的问题,请参见另一篇博文: 使用严苛模式打破Android4.0以上平台应用中UI主线程的“独断专行”。
有关工作线程的处理方式,这里推荐使用定制线程池的方式,核心代码如下:
[java] view plain print ?
// 线程池初始容量
private static final int POOL_SIZE = 4;
private ExecutorService executorService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 获取当前使用设备的CPU个数
int cpuNums = Runtime.getRuntime().availableProcessors();
// 预开启线程池数目
executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE);
...
executorService.submit(new Runnable() {
// 此处执行一些耗时工作,不要涉及UI工作。如果遇到,直接转交UI主线程
pano.setImage(loadBitmap(url));
});
...
}
我们知道,线程构造也是比较耗资源的。一定要对其进行有效的管理和维护。千万不要随意而行,一张图片的工作线程不搭理也许没什么,当使用场景变为 ListView和GridView时,线程池化工作就显得尤为重要了。Android不是提供了AsyncTask吗?为什么不用它?其实 AsyncTask底层也是靠线程池支持的,它默认分配的线程数是128,是远大于我们定制的executorService。
2. Android Bitmap理解
参考:
Android Bitmap 详解:关于 Bitamp 你所要知道的一切
Android Bitmap(位图)详解
图片是由大量且有限个数的像素点组成。把一张图片通过bitmap的方式创建到内存中,实际上就是在内存中创建了一个叫做Bitmap的对象,然后把 图片所有像素 解码后的数据存放在Bitmap对象里面,Bitmap就拥有了图片的宽高,透明度,颜色值等数据。所以Bitmap的创建是通过BitmapFactory.decodeXxx()。
Config是Bitmap类中的枚举类。像素由ARGB四个颜色通道组成。Config描述位图中像素的存储方式。 这里的存储方式,无非就是对颜色通道和用多大的容器(bit)来存储的排列组合。所以config会影响图片透明度,占用内存大小,保存成文件的大小,图片质量。
Config的字母表示该配置存储的像素的颜色通道,数字表示对应通道的数据用多少位来存储。
ALPHA_8:表示只存储alpha通道,使用8bit(1字节)的内存(容器)来存储一个像素。
RGB_565:表示存储RGB三个通道,分别使用5bit,6bit,5bit的内存(容器)来存储一个像素。
ARGB_4444:表示存储ARGB四个通道,每个通道都是以4bit的内存(容器)来存储一个像素。
ARGB_8888:表示存储ARGB四个通道,每个通道都是以8bit的内存(容器)来存储一个像素。
所以,ARGB_8888配置占用内存最大,图片质量最高。
图片压缩的一个思路就是降低图片的配置。
总内存 = 宽的像素数 × 高的像素数 × 每个像素点占用的大小
注:
1 byte = 8 bit
1 KB = 1024 byte
3. android中怎么用sqlite存储一个map
在进行Android开发过程中,我们经常会接触到Drawable对象(官方开发文档:A Drawable is a general abstraction for "something that can be drawn."),那么,若要使用数据库来进行存储及读取,该如何实现?
一、存储
//第一步,将Drawable对象转化为Bitmap对象
Bitmap bmp = (((BitmapDrawable)tmp.image).getBitmap());
//第二步,声明并创建一个输出字节流对象
ByteArrayOutputStream os = new ByteArrayOutputStream();
//第三步,调用compress将Bitmap对象压缩为PNG格式,第二个参数为PNG图片质量,第三个参数为接收容器,即输出字节流os
bmp.compress(Bitmap.CompressFormat.PNG, 100, os);
//第四步,将输出字节流转换为字节数组,并直接进行存储数据库操作,注意,所对应的列的数据类型应该是BLOB类型
ContentValues values = new ContentValues();
values.put("image", os.toByteArray());
db.insert("apps", null, values);
db.close();
4. bitmap能存放的最大数据是多少
redis的bitmap能设置最大的长度是多少, 为什么可以设置的最大长度位数是2^32, 怎么计算bitmap会占用多大的空间
前提: 实际上, redis只支持5种数据类型. 并没有bitmap. 也就是bitmap是基于redis的字符串类型的. 而一个字符串类型最多存储512M.
首先: 计算机的单位换算先了解下
8 bit = 1byte
1024 byte = 1kb
1024 kb = 1Mb
其次:
我们使用的bitmap指令SETBIT key offset value, 这个指令就是将第offset设置成0或1. 比如 SETBIT ss 1000 1 //就是将1000位置为1. 1 bit就是1位, 所以我们只要将512M换算成bit, 那么就知道bitmap支持的最大设置长度了. 计算如下
8 * 1024 * 1024 * 512 = 2^32 (所以这个结果就是这么来的)
怎么计算自己的bitmap会大概占用多大的存储空间呢?
举个栗子: 今有一个bitmap最大长度1024, 需要占用多大的空间?
解: 长度1024也就是他需要1024个位(bit), 或者单位为byte就是需要 1024 / 8, 即需要128byte
————————————————
版权声明:本文为CSDN博主“Day____Day____Up”的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37281289/article/details/106834014