Android進(jìn)階之Bitmap的高效加載

一、Bitmap的加載

BitmapFactory提供了四個(gè)方法:

  • docodeFiles
  • decodeResource
  • decodeStream
  • decodeByteArray

二、Bitmap的高效加載

采用Bitmap.Options來(lái)加載所需尺寸的圖片,主要使用它的inSampleSize參數(shù),當(dāng)inSampleSize大于1縮放。(inSampleSize會(huì)向下去2的指數(shù))
高效加載圖片的流程:

  1. 將BitmapFactory.Options的inJustDecodeBuunds設(shè)為true并加載圖片
  2. 從Bitmap.Options中取出圖片的寬高(outHeight,outWidth)
  3. 結(jié)合ImageView的寬高計(jì)算采樣率
  4. 將BitmapFatory.Options中的inJustDecodeBounds設(shè)為false并加載圖片
    示例:
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ImageView image=findViewById(R.id.image1);
   image.setImageBitmap(sampleDecodeFromResourse(getResources(),R.mipmap.dog,200,200));
    }
    public static Bitmap sampleDecodeFromResourse(Resources res,int resId,int repWidth,int repHeight){
        final BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeResource(res,resId,options);
        options.inSampleSize=computeInSampleSize(options,repWidth,repHeight);
        options.inJustDecodeBounds=false;
        Bitmap bitmap=BitmapFactory.decodeResource(res,resId,options);
        return bitmap;
    }
    public static int computeInSampleSize(BitmapFactory.Options options,int repWidth, int repHeight){
        final int width=options.outWidth;
        final int height=options.outHeight;
        int inSampleSize=1;
        if(width>repWidth||height>repHeight){
            int sampleWidth=((int)width/repWidth)%2==0?width/repWidth+2:width/repWidth+1;
            int sampleHeight=((int)height/repHeight)%2==0?height/repHeight+2:height/repHeight+1;
            inSampleSize=(int)Math.max(sampleWidth,sampleHeight);
        }
        return inSampleSize;
    }
}

三、Android中的緩存策略

常用的緩存算法LRU算法,包括:LruCache和DiskLruCache
LruCache用于內(nèi)存緩存
DiskLruCache用于存儲(chǔ)設(shè)備緩存

(1)LruCache

LruCache是Android提供的一個(gè)緩存類(lèi),它是一個(gè)泛型類(lèi),內(nèi)部采用LinkedHashMap以強(qiáng)引用的方式存儲(chǔ)外界對(duì)象。
LruCache典型初始化:

int maxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
int cacheSize=maxMemory/8;
mMemoryCache=new LruCache<String,Bitmap>(cacheSize){
protected int sizeOf(String key,Bitmap bitmap){
return bitmap.getByteCount();
}
}

添加一個(gè)緩存對(duì)象

mMemoryCache.put(key,value);

獲取一個(gè)緩存對(duì)象

mMemory.get(key);
(2)DiskLruCache

DiskLruCache用于設(shè)備的存儲(chǔ),及磁盤(pán)緩存。需要添加依賴(lài):

implementation 'com.jakewharton:disklrucache:2.0.2'

DiskLruCache的建立:

Private static final int CACHE_SIZE=1024*1024*50;
File diskCacheDir=getDiskCacheDir(mContext,"bitmap");
if(!diskCacheDir.exists())

首先獲取Url所對(duì)應(yīng)的Key,再根據(jù)key通過(guò)edit()方法獲取Editor對(duì)象,一般key取url的MD5值

private String hashKeyFormUrl(String url){
String hashKey;
try{
final MessageDigest mDigest=MessageDigest.getInstance("MD5");
mDigest.upDtate(url.getByte());
hashKey=bytesToHexString(mDigest.digest());
}catch(NoSuchAlgorithmException e){
hashKey=String.valueOf(url.hashCode());
}
return hashKey;
}
private String bytesToHexString(byte[] bytes){
StringBuffer buffer=new StringBuffer();
for(int i=0;i<bytes.length;i++){
String hex=Integer.toHexString(0xFF&bytes[i]);
if(hex.length==1){
buffer.append('0');
}
buffer.append(hex);
}
return buffer;
}

獲取Editor對(duì)象

String key=hashFormUrl(url);
DiskLruCache.Editor editor=mDiskLruCache.edit(key);
if(editor!=null){
OutputStream outputStream=editor.newOutputStream(DISK_CACHE_INDEX);
}

存入緩存對(duì)象

public boolean downloadUrlToStream(String url,OutputStream outputStream){
HttpURLConnection connection=null;
BufferedOutputStream out=null;
BufferedInputStream int=null;
try{
final URL url=new URL(url);
connection=(HttpURLConnection)url.openConnection();
in=new BufferedInputStream(connection.getInputStream(),1024*10);
out=new BufferedOutputStream(output,1024*10);
int b;
while((b=in.read())!=-1){
out.write(b);
}
return true;
}catch(IOException e){
e.printStackTrace();
}finally{
if(connection!=null){
connection.disConnection();
}
if(in!=null){
try{
in.close();
}catch(IOException e){
e.printStackTrace();
}
}
if(out!=null){
try{
out.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}

提交

OutputStream outputStream=editor.newOutputStream(DISK_CACHE_INDEX);
if(downloadUrlToStream(url,outputStream)){
editor.commit();
}else{
editor.abort();
}
mDiskLruCache.flush();

提取

Bitmap bitmp=null;
String key=hashKeyFormUrl(url);
DiskLruCache.Snapshot snapshot=mDiskLruCache.get(key);
if(snapshot!=null){
FileInputStream fileInputStream=(FileInputStream)snapshot.getInputStream(DISK_CACHE_INDEX);
FileDescriptor fileDescriptor=fileInputStream.getFD();//由于使用流解析存在問(wèn)題,所以采取流對(duì)應(yīng)的文件描述符來(lái)解析
bitmap=decodeSampleedBitmapFromFileDescriptor(fileDescriptor,repWidth,repHeight);//自己寫(xiě)的高效加載圖片的方法和前面的一樣只是解析方法不一樣
if(bitmap!=null){
addBitmapTomemoryCache(key,bitmap);
}
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,996評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,316評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,406評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,128評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,524評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,759評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,310評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,065評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,249評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,479評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,909評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,140評(píng)論 1 290
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,984評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,228評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容