利用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);
	}

}

 

时间: 2024-12-27 15:02:09

利用SoftReference实现图片异步加载的相关文章

Android-Universal-Image-Loader 图片异步加载类库的使用

在博客中看到一篇利用组件进行图片异步加载的文章在此作记录 原文:http://blog.csdn.net/vipzjyno1/article/details/23206387 这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影.        可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和

Android优化双缓存的图片异步加载工具(LruCache+SoftReference)

之前在郭大神的博客看到使用LruCache算法实现图片缓存的.这里仿效他的思路,自己也写了一个. 并加入ConcurrentHashMap<String, SoftReference<Bitmap>>去实现二级缓存,因为ConcurrentHashMap是多个锁的线程安全,支持高并发.很适合这种频繁访问读取内存的操作. 下面整个思路是,使用了系统提供的LruCache类做一级缓存, 大小为运行内存的1/8,当LruCache容量要满的时候,会自动将系统移除的图片放到二级缓存中,但为

ios UITableView封装之下拉-上提-图片异步加载

写在前面 做过移动端开发的人都知道,列表控件是最常用的控件之一.iOS里的列表控件是UITableView,其实Apple的开发人员对于UITableView的设计已经够好的了(简单易用,扩展性非常强等等). 但对于展示逻辑单一的移动端系统软件,你还是能感觉到有些繁琐(或许是程序员天生就有些懒惰的毛病吧). 来看看它到底繁琐在哪儿了.首先,它的使用频率太高了:第二,它通常不是只呈现一下数据就完事了,一般都会跟随下拉刷新.上提加载更多功能,当然通常还要跟网络下载数据.图片打交道:第三,MVC模式是

listview-Android ListView图片异步加载和上拉加载

问题描述 Android ListView图片异步加载和上拉加载 我的ListView设置一个OnScrollListener,然后更加可见的item数目来异步加载图片,和缓存图片, 但同时这个ListView又是个第三方的带上拉加载的,第三方的代码里也注册了OnScrollListener, 因此这两个OnScrollListener,只能有一个生效,但我想把上拉加载和异步加载图片的逻辑, 都写在同一个OnScrollListener,有什么好的设计吗? 问题在于上拉加载是在第三方的库中,而异

Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

       这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影.        可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和配置.          GITHUB上的下载路径为:https://github.com/nostra13/Android-Universal-Image-Lo

Android-Universal-Image-Loader图片异步加载并缓存

 这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影.        可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和配置.          GITHUB上的下载路径为:https://github.com/nostra13/Android-Universal-Image-Loader ,

Android图片异步加载框架Android-Universal-Image-Loader

Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个Android开源项目之一,主流的应用,随便反编译几个,都可以见到它的身影.淘宝,天猫,Facebook,京东商城等都用到了这个项目.该项目的Github地址链接:https://github.com/nostra13/Android-Universal-Image-Loader 运行流程:每一个图片的加载和显示任务都运行在独立的线程中,除非这个图片缓存

Android图片异步加载

开发Android程序,一般情况下都会有两个操作,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操作),为了减少网络操作,加快图片加载速度就需要对图片进行缓存,所以网上的好多图片异步加载方法都是与图片的缓存紧密关联的.但也有可能用户已经有了缓存的相关类库,这样使用起来就会有点麻烦. 最近一段处理跟图片相关的问题,本来是自己写的图片加载,不过有些状态的控制还是比较烦人的,比如ListView滚动时ImageView的重用,所以本着偷懒与充分利用现有资源的态度去

android图片异步加载到本地

package com.example.health.util; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.content.