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