利用SoftReference实现图片异步加载

//以下是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(){
			@Override
			public 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);
			}};
			
		//新开辟一个线程,该线程用于进行图片的下载
		//这个下载是一个异步的操作。我们无法等到线程完毕后来获取对象
		//所以需要一个机制:当下载完成后收到相应的通知。所以才有了handle
		new Thread(){
			@Override
			public 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;
	}
	@Override
	public void showLoadedImage(Drawable imageDrawable) {
	         imageView.setImageDrawable(imageDrawable);
	}

}



 

你可能感兴趣的:(利用SoftReference实现图片异步加载)