//以下是mars講解的軟引用
對象存在與堆中,對象的引用存在於棧中
比如:
Object obj=new Object()//obj在棧中
obj=null
當堆記憶體中的對象沒有任何引用指向時,記憶體回收機制會回收此塊記憶體.即當obj=null時.
軟引用:
可以保證記憶體回收機制,但是同時這個引用指向塊堆裡的記憶體.所以叫軟引用.
調用 Object obj=sr.get()時,假若這個對象已經被回收那麼get()方法將會返回null
可以採用MAP作為緩衝.緩衝裡存放的是索引值對,鍵是圖片的url,值是這張圖片對象的軟引用
當圖片不在緩衝裡時才去網路上擷取,若在直接從緩衝裡擷取.
提醒:網路許可權<uses-permission android:name="android.permission.INTERNET"/>
//以上是mars講解的軟引用
//以下是網路文章關於軟引用的講解
//參考資料
http://blog.csdn.net/helixiuqqq/article/details/6610199
http://blog.csdn.net/qeqeqe236/article/details/7289119
http://blog.csdn.net/shang_515/article/details/7020027
http://blog.csdn.net/lvron/article/details/6721230
http://blog.csdn.net/sgl870927/article/details/6285535
如果一個對象只具有軟引用,則記憶體空間足夠,記憶體回收行程就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體.只要記憶體回收行程沒有回收它,該對象就可以被程式使用.軟引用可用來實現記憶體敏感的快取.
為什麼需要使用軟引用?
首先,我們看一個僱員資訊查詢系統的執行個體.我們將使用一個Java語言實現的僱員資訊查詢系統查詢儲存在磁碟檔案或者資料庫中的僱員人事檔案資訊.作為一個使用者,我們完全有可能需要回頭去查看幾分鐘甚至幾秒鐘前查看過的僱員檔案資訊(同樣,我們在瀏覽WEB頁面的時候也經常會使用[上一頁] 按鈕).這時我們通常會有兩種程式實現方式:一種是把過去查看過的僱員資訊儲存在記憶體中,每一個儲存了僱員檔案資訊的Java對象的生命週期貫穿整個應用程式始終;另一種是當使用者開始查看其他僱員的檔案資訊的時候,把儲存了當前所查看的僱員檔案資訊的Java對象結束引用,使得垃圾收集線程可以回收其所佔用的記憶體空間,當使用者再次需要瀏覽該僱員的檔案資訊的時候,重新構建該僱員的資訊.很顯然,第一種實現方法將造成大量的記憶體浪費,而第二種實現的缺陷在於即使垃圾收集線程還沒有進行垃圾收集,包含僱員檔案資訊的對象仍然完好地儲存在記憶體中,應用程式也要重新構建一個對象.我們知道,訪問磁碟檔案、訪問網路資源、查詢資料庫等操作都是影響應用程式執行效能的重要因素,如果能重新擷取那些尚未被回收的Java對象的引用,必將減少不必要的訪問,大大提高程式的運行速度.
如何使用軟引用?
SoftReference的特點是它的一個執行個體儲存對一個Java對象的軟引用,該軟引用的存在不妨礙垃圾收集線程對該Java對象的回收.也就是說,一旦SoftReference儲存了對一個Java對象的軟引用後,在垃圾線程對這個Java對象回收前,SoftReference類所提供的get()方法返回Java對象的強引用.另外,一旦垃圾線程回收該Java對象之後,get()方法將返回null.
//以上是網路文章關於軟引用的講解
以下為執行個體代碼//main.xml如下<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scrollview" android:layout_width="fill_parent" android:layout_height="wrap_content" > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imageView2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imageView3" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imageView4" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imageView5" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout></ScrollView>//Activity如下package cn.com;import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.widget.ImageView;public class SoftReferenceImageLoaderActivity extends Activity { AsyncImageLoader asyncImageLoader=new AsyncImageLoader(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loadImages("http://photocdn.sohu.com/20120523/Img343875294.jpg", R.id.imageView1); loadImages("http://photocdn.sohu.com/20120523/Img343866809.jpg", R.id.imageView2); loadImages("http://photocdn.sohu.com/20120523/Img343875296.jpg", R.id.imageView3); loadImages("http://photocdn.sohu.com/20120523/Img343875299.jpg", R.id.imageView4); loadImages("http://photocdn.sohu.com/20120523/Img343875302.jpg", R.id.imageView5); } private void loadImages(String imageUrl,int imageViewID){ ImageView imageView=(ImageView) findViewById(imageViewID); ImageCallbackImpl imageCallbackImpl=new ImageCallbackImpl(imageView); //非同步載入圖片 //分析: //1 如果圖片在緩衝中,那麼我們在調用loadImages()時,在該方法的第一個if判斷時就返回了 // 一個Drawable對象,當然其不為空白.所以我們此處直接執行: // if(loadPicture!=null){ // imageView.setImageDrawable(loadPicture); // } //2 若圖片不在緩衝中那麼就需要從網路下載. // 請注意:loadImages()方法中的Handle+Thread一個非同步機制,這個時候返回的是null!!!!!!!!!!! // 所以不會執行: // if(loadPicture!=null){ // imageView.setImageDrawable(loadPicture); // } // 但是不要緊因為我們在方法loadImages()中執行了imageCallbackImpl.showLoadedImage(drawable); // 也達到了目的 // 所以這個回調是設計得很巧妙的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Drawable loadPicture=asyncImageLoader.loadImages(imageUrl, imageCallbackImpl); if(loadPicture!=null){ imageView.setImageDrawable(loadPicture); } }}//核心類如下package cn.com;import java.io.IOException;import java.lang.ref.SoftReference;import java.net.URL;import java.util.HashMap;import java.util.Map;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;public class AsyncImageLoader {//Map<String, SoftReference<Drawable>>利用了Map來實現圖片緩衝!!!//鍵是圖片的URL,值是一個SoftReference對象,該對象是一個引用指向一個Drawable對象!!!!!!!!!!!!!//當然這個值不是一個真正的圖片,只是圖片對象的引用.否則 記憶體很容易就滿了private Map<String,SoftReference<Drawable>> imageCatch=new HashMap<String, SoftReference<Drawable>>();//回調介面.圖片載入完成後會執行此方法進行顯示public interface ImageCallback{public void showLoadedImage(Drawable imageDrawable);}//根據圖片的URL,從網路上下載圖片,並產生一個Drawable對象返回private Drawable loadImageFromURL(String imageURL){try {return Drawable.createFromStream(new URL(imageURL).openStream(), "src");} catch (IOException e) {e.printStackTrace();}return null;}//以下為核心代碼public Drawable loadImages(final String imageUrl,final ImageCallback imageCallbackImpl){if(imageCatch.containsKey(imageUrl)){//如果圖片還在緩衝中SoftReference<Drawable> softReference=imageCatch.get(imageUrl);if(softReference!=null){//軟引用還在return softReference.get();//返回軟引用指向的對象.此時loadImages()方法結束}}//這也是匿名內部類的一種寫法!!!!//如果不在緩衝中,就該如下操作:final Handler handler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Drawable drawable=(Drawable) msg.obj;//因為內部類訪問外部變數所以參數imageUrl和imageCallback要有final修飾//在Activity裡面ImageCallbackImpl imageCallbackImpl=new ImageCallbackImpl(imageView);//然後在調用loadImages()方法時,將其作為參數傳遞給了過來.imageCallbackImpl.showLoadedImage(drawable);}};//新開闢一個線程,該線程用於進行圖片的下載//這個下載是一個非同步操作。我們無法等到線程完畢後來擷取對象//所以需要一個機制:當下載完成後收到相應的通知。所以才有了handlenew Thread(){@Overridepublic void run() {super.run();//因為內部類訪問外部變數所以參數imageUrl和imageCallback要有final修飾Drawable drawable=loadImageFromURL(imageUrl);imageCatch.put(imageUrl,new SoftReference<Drawable> (drawable));//下載後放到緩衝裡面Message message=new Message();message.obj=drawable;//因為內部類訪問外部變數所以變數handle要有final修飾handler.sendMessage(message);}}.start();return null;//這裡不能返回此drawable. //因為這個下載是一個非同步過程,很可能執行到此return語句時圖片還沒有下載完!}}//介面實作類別如下:package cn.com;import android.graphics.drawable.Drawable;import android.widget.ImageView;import cn.com.AsyncImageLoader.ImageCallback;public class ImageCallbackImpl implements ImageCallback {private ImageView imageView;//構造方法public ImageCallbackImpl(ImageView imageView) {super();this.imageView = imageView;}@Overridepublic void showLoadedImage(Drawable imageDrawable) { imageView.setImageDrawable(imageDrawable);}}