檔案快取與記憶體快取
阿新 • • 發佈:2019-02-07
<strong><span style="font-size:24px;">1.java的引用型別:</span></strong>
<p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋體; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);">1)強引用(StrongReference) 強引用是使用最普遍的引用。如果一個物件具有強引用,那垃圾回收器絕不會回收它。當記憶體空間不足,Java<a target=_blank href="http://www.2cto.com/os/xuniji/" target="_blank" class="keylink" style="color: rgb(51, 51, 51); text-decoration: none;">虛擬機器</a>寧願丟擲OutOfMemoryError錯誤,使程式異常終止,也不會靠隨意回收具有強引用的物件來解決記憶體不足的問題。 2)軟引用(SoftReference) 如果一個物件只具有軟引用,則記憶體空間足夠,垃圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些物件的記憶體。只要垃圾回收器沒有回收它,該物件就可以被程式使用。軟引用可用來實現記憶體敏感的快取記憶體(下文給出示例)。 軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收器回收,Java虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中。</p><p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋體; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);">3) 弱引用(WeakReference) 弱引用與軟引用的區別在於:弱引用的物件擁有更短暫的生命週期。在垃圾回收器執行緒掃描它所管轄的記憶體區域的過程中,一旦發現了只具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於垃圾回收器是一個優先順序很低的執行緒,因此不一定會很快發現那些只具有弱引用的物件。 弱引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果弱引用所引用的物件被垃圾回收,Java虛擬機器就會把這個弱引用加入到與之關聯的引用佇列中。</p><p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋體; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);"> 4)虛引用(PhantomReference) “虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定物件的生命週期。如果一個物件僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。 虛引用主要用來跟蹤物件被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用佇列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收物件的記憶體之前,把這個虛引用加入到與之 關聯的引用佇列中。</p>----
軟引用:
結合載入歌手圖片來說明:
1.先建立一個MAP集合,用來儲存圖片的快取檔案
<pre name="code" class="html"> //記憶體快取 使用軟引用
private Map<String, SoftReference<Bitmap>> softcache=new HashMap<String, SoftReference<Bitmap>>();
2.使用時 先在獲取到圖片的Bitmap資料位置進行資料的放入快取操作。
3.快取原理就是:如果檔案在快取中有,就直接從快取中獲取資料,由於是軟引用,當系統記憶體不足時,記憶體回收機制GC就可能會銷燬掉部分快取資料,沒有時,才需要重新載入圖片資料。所以在adapter的getview中 先判斷後、然後就可以直接使用控制元件載入bitmap資料<span style="white-space:pre"> </span>//將獲取的bitmap存入記憶體快取 softcache.put(task.imagePath, new SoftReference<Bitmap>(bitmap));
//先去記憶體快取檢視是否有此圖的快取圖片 SoftReference<Bitmap> ref= softcache.get(path); //獲取快取中的快取物件 if(ref!=null){ //從快取物件中取出快取圖片 Bitmap b= ref.get(); if(b!=null){//有圖 holder.ivImage.setImageBitmap(b); //直接載入記憶體的快取的圖片 Log.d("tedu", "從記憶體快取讀取。。"); return convertView ;//有則直接返回 } }
<strong><span style="font-size:18px;">2.檔案引用</span></strong>
檔案引用就是將開始讀取的資料放入app對應的快取資料夾內,當下次讀取時,就可以直接載入顯示 節省流量。
1.先建立兩個方法,一個是用於儲存資料到快取,一個是用於通過快取檔案路徑去取出資料用於顯示
<pre name="code" class="html"> //用於儲存檔案
public static void saveMap(Bitmap bitmap,File file) throws FileNotFoundException{
if(!file.getParentFile().exists()){
//獲取父目錄資料夾是否存在,不存在就建立
file.getParentFile().mkdirs();
}
//建立檔案輸出流 儲存檔案
FileOutputStream fos=new FileOutputStream(file);
//將bitmap檔案壓縮並輸出
bitmap.compress(CompressFormat.JPEG, 100, fos);
}
<span style="white-space:pre"> </span>//用於獲取資料的方法
<pre name="code" class="html"> public static Bitmap getBitmapByFile(File file){
if(!file.exists()){
return null;
}
//根據檔案去找到檔案快取中的圖片、
Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
return bitmap;
}
2.然後與軟引用一樣。在獲取到資料的位置,呼叫儲存方法,將資料放入快取檔案件夾內:
<pre name="code" class="html"><span style="white-space:pre"> </span>//將獲取的圖再存入檔案快取中
String path=task.imagePath;//獲取當前任務中的檔案路徑
String filename=path.substring(path.lastIndexOf("/")+1);//不包含/
File file=new File(context.getCacheDir(), "images/"+filename);
//呼叫方法 儲存檔案
BitMapUtil.saveMap(bitmap, file);
3.同樣的方法,在getview中判斷後 就可以直接使用控制元件進行資料的顯示:
<span style="white-space:pre"> </span>//從檔案中讀取圖片
String filename=path.substring(path.lastIndexOf("/")+1);
File file=new File(context.getCacheDir(),"images/"+filename);
Bitmap map=BitMapUtil.getBitmapByFile(file);
if(map!=null){
holder.ivImage.setImageBitmap(map);
Log.d("tedu", "從檔案快取讀取。。");
//從檔案讀時同時儲存到記憶體快取。加快讀取速度
softcache.put(path, new SoftReference<Bitmap>(map));
return convertView;
}
上面這段程式碼中,加了一句當從檔案獲取資料快取資料時,重新將資料放入記憶體的快取集合中 ,這樣可以加快圖片的顯示,從記憶體中獲取是最快的!
原碼:
package com.wuxs.three_musicplayer_v4.Adapter;
import java.io.File;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.wuxs.three_musicplayer_v4.R;
import com.wuxs.three_musicplayer_v4.entity.Music;
import com.wuxs.three_musicplayer_v4.util.BitMapUtil;
import com.wuxs.three_musicplayer_v4.util.MusicHttpUtil;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class MusicsAdapter extends BaseAdapter {
private Context context;
private List<Music> musics;
private LayoutInflater inflater;
private ListView lvmusic;// 為了獲取標記的imageview
//建立任務集合。
private List<LoadImageTask> tasks=new ArrayList<LoadImageTask>();
private Thread thread;
private boolean isLoop=true;
//記憶體快取 使用軟引用
private Map<String, SoftReference<Bitmap>> softcache=new HashMap<String, SoftReference<Bitmap>>();
private Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case LOAD_IMAGE_SUCCESS: //載入ok
LoadImageTask task= (LoadImageTask) msg.obj;
Bitmap bitmap= task.bitmap; //資料ok
//取出
ImageView ivImage= (ImageView) lvmusic.findViewWithTag(task.imagePath);
if(ivImage!=null){
if(bitmap!=null){
ivImage.setImageBitmap(bitmap);
}
}
break;
}
return false;
}
});
private static final int LOAD_IMAGE_SUCCESS=1;
public MusicsAdapter(final Context context, List<Music> musics,ListView lvmusic) {
super();
this.context = context;
this.musics = musics;
this.inflater = LayoutInflater.from(context);
this.lvmusic=lvmusic;
thread=new Thread(){
@Override
public void run() {
//在工作執行緒處理載入任務
while(isLoop){//讓他不斷迴圈判斷 類似handler的looper
if(!tasks.isEmpty()){//如果任務集合不為空
//獲取bitmap資料
LoadImageTask task=tasks.remove(0); //每次移除第一個任務出來
// Bitmap bitmap=getBitMap(task.imagePath);//改為採用壓縮格式圖片獲取
try {
Bitmap bitmap = BitMapUtil.getYasuoPhoto(task.imagePath,40,40);
//將bitmap資料封裝進去
task.bitmap=bitmap;
//在這個位置獲取了圖片的bitmap資訊 在此加上記憶體快取
//將獲取的bitmap存入記憶體快取
softcache.put(task.imagePath, new SoftReference<Bitmap>(bitmap));
//將獲取的圖再存入檔案快取中
String path=task.imagePath;//獲取當前任務中的檔案路徑
String filename=path.substring(path.lastIndexOf("/")+1);//不包含/
File file=new File(context.getCacheDir(), "images/"+filename);
//呼叫方法 儲存檔案
BitMapUtil.saveMap(bitmap, file);
} catch (Exception e) {
e.printStackTrace();
}
//發出訊息
Message mes=Message.obtain();
mes.what=LOAD_IMAGE_SUCCESS;
mes.obj=task;
handler.sendMessage(mes);
}else{
//任務為空時 ,讓執行緒休眠
synchronized (thread) {
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
thread.start();
}
//獲取bitmap
protected Bitmap getBitMap(String imagePath) {
//呼叫方法
try {
String url=imagePath;
InputStream is= MusicHttpUtil.getXmlInputStream(url);
Bitmap bitmap=BitmapFactory.decodeStream(is);//通過輸入流獲取圖片bitmap資料
return bitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return musics.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return musics.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Music music=musics.get(position);
viewHolder holder=null;
if(convertView==null){
convertView=inflater.inflate(R.layout.list_m, null);
holder=new viewHolder();
holder.ivImage=(ImageView) convertView.findViewById(R.id.ivphoto);
holder.tvAuthor=(TextView) convertView.findViewById(R.id.tv_author);
holder.tvTitle=(TextView) convertView.findViewById(R.id.tv_title);
convertView.setTag(holder);
}else {
holder=(viewHolder) convertView.getTag();
}
holder.tvAuthor.setText(music.getAuthor());
holder.tvTitle.setText(music.getTitle());
//標記每個imageview
String path=music.getPic_small();
holder.ivImage.setTag(path); //用small路徑去標記imageview
//先去記憶體快取檢視是否有此圖的快取圖片
SoftReference<Bitmap> ref= softcache.get(path); //獲取快取中的快取物件
if(ref!=null){
//從快取物件中取出快取圖片
Bitmap b= ref.get();
if(b!=null){//有圖
holder.ivImage.setImageBitmap(b); //直接載入記憶體的快取的圖片
Log.d("tedu", "從記憶體快取讀取。。");
return convertView ;//有則直接返回
}
}
//從檔案中讀取圖片
String filename=path.substring(path.lastIndexOf("/")+1);
File file=new File(context.getCacheDir(),"images/"+filename);
Bitmap map=BitMapUtil.getBitmapByFile(file);
if(map!=null){
holder.ivImage.setImageBitmap(map);
Log.d("tedu", "從檔案快取讀取。。");
//從檔案讀時同時儲存到記憶體快取。加快讀取速度
softcache.put(path, new SoftReference<Bitmap>(map));
return convertView;
}
//沒有則繼續發任務 子執行緒中獲取圖片
//在這裡不能直接使用子執行緒來顯示圖片。應為那樣會建立很多個執行緒、改為在構造方法時建立子執行緒。就會建立一個
//在這裡要做的事就是發出一個圖片顯示任務,然後給到子執行緒,去處理。
LoadImageTask task=new LoadImageTask();
task.imagePath=music.getPic_small(); //將路徑設定進去
//然後往集合裡新增該task。 也就是發出了一個圖片載入任務
tasks.add(task);
//喚醒休眠後的執行緒
synchronized (thread) {
thread.notify(); //喚醒執行緒
}
return convertView;
}
class viewHolder{
ImageView ivImage;
TextView tvTitle;
TextView tvAuthor;
}
//設定任務屬性
private class LoadImageTask{
private String imagePath;
private Bitmap bitmap;
}
//停止執行緒方法
public void StopThread(){
isLoop=false; //停止子執行緒
//如果執行緒在休眠 就喚醒
synchronized (thread) {
thread.notify();
}
}
}