android 新闻图片加载,缓存处理

在Android开发中,为了快速高效地展示大量图片,通常会采用缓存策略。本文介绍了三种方法:1) 网络下载,通过多线程后台加载并在Handler中更新界面;2) 本地文件加载,直接根据图片路径获取Bitmap;3) 缓存中读取,利用WeakHashMap作为缓存,实现图片的弱引用存储,避免内存泄漏。同时,提供了结合以上方法的ImageCache.java文件,用于图片缓存的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发中,遇到很多大量图片呈现给用户,那么我们怎么又快又高效的显示给用户呢?

在这里结合前人写的文章和自己的一些改动。

一般我们写的过程中是这么处理的:先去缓存(WeakHashMap<String, Bitmap>来存储图片)中提取,这样速度快又节约流量,缓存中没有再选择本地有图片没有,如果两者都没有则只有从网络去获取。

我们先分开讲解

方法一:网络下载

方法二:从本地文件加载

方法三:从缓存中读取


先来说方法一:

加载很多图片的时候,我们经常用多线程在后台下载,在handler中将图片呈现在界面。

直接上代码

//网络获取图片
   protected Bitmap getNetBitmapByURL(String urlString) {
		URL url = null;
		InputStream inputStream = null;
		HttpURLConnection urlConnection = null;
		Bitmap bmp = null;
		try {
			url = new URL(urlString);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.setRequestMethod("GET");
			urlConnection.setConnectTimeout(10000);
			inputStream = urlConnection.getInputStream();
			byte[] bt = getBytesFromStream(inputStream);
			bmp = BitmapFactory.decodeByteArray(bt, 0, bt.length);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != inputStream) {
				try {
					inputStream.close();
					inputStream = null;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != urlConnection) {
				urlConnection.disconnect();
				urlConnection = null;
			}
		}
		return bmp;
	}

	// 数据流
	private byte[] getBytesFromStream(InputStream inputStream) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while (len != -1) {
			try {
				len = inputStream.read(b);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (len != -1) {
				baos.write(b, 0, len); 
			}
		}
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return baos.toByteArray();
	}
这个地方获取了Bitmap  用handler呈现就很好搞定


再来说方法二本地获取:

直接根据图片路径获取Bitmap


private boolean cacheBmpToMemory(File file) {
		boolean sucessed = true;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			sucessed = false;
		}
		byte[] bs = getBytesFromStream(inputStream);
		Bitmap bitmap = BitmapFactory.decodeByteArray(bs, 0, bs.length);
		if (bitmap == null) {
			return null;
		}
		return bitmap;
	}
private byte[] getBytesFromStream(InputStream inputStream) {
		boolean b2 = true;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while (len != -1 && b2) {
			try {
				len = inputStream.read(b);
				if (len != -1) {
					baos.write(b, 0, len);
				}
			} catch (IOException e) {
				b2 = false;
				try {
					inputStream.close();
				} catch (IOException e1) {
				}
			}

		}

		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return baos.toByteArray();
	}




方法三缓存获取:
用弱引用:WeakHashMap<String, Bitmap>,以弱键 实现的基于哈希表的 Map,在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除。
WeakHashMap 中的每个键对象间接地存储为一个弱引用的指示对象。因此,不管是在映射内还是在映射之外,只有在垃圾回收器清除某个键的弱引用之后,该键才会自动移除
这个地方结合方法一和方法二,写了一个有关图片缓存的解决方法。


java文件:

ImageCache.java

package com.imageService;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.WeakHashMap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.os.Environment;


public class ImageCache extends WeakHashMap<String, Bitmap> {

	private static ImageCache mNetImageViewCache = new ImageCache();
	private static final String CACHE_FILE = "/Cache";

	private ImageCache() {

	}

	public static ImageCache getInstance() {
		return mNetImageViewCache;
	}

	/**
	 * 判断图片是否存在首先判断内存中是否存在然后判断本地是否存在
	 * 
	 * @param url
	 * @return
	 */
	public boolean isBitmapExit(String url) {
		boolean isExit = containsKey(url);
		if (false == isExit) {
			isExit = isLocalHasBmp(url);
		}
		return isExit;
	}

	/*
	 * 判断本地有没有
	 */
	private boolean isLocalHasBmp(String url) {
		boolean isExit = true;

		String name = changeUrlToName(url);
		String filePath = isCacheFileIsExit();

		File file = new File(filePath, name);

		if (file.exists()) {
			isExit = cacheBmpToMemory(file, url);
		} else {
			isExit = false;
		}
		return isExit;
	}

	/*
	 * 将本地图片缓存到内存中
	 */
	private boolean cacheBmpToMemory(File file, String url) {
		boolean sucessed = true;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			sucessed = false;
		}
		byte[] bs = getBytesFromStream(inputStream);
		Bitmap bitmap = BitmapFactory.decodeByteArray(bs, 0, bs.length);
		if (bitmap == null) {
			return false;
		}
		this.put(url, bitmap, false);
		return sucessed;
	}

	private byte[] getBytesFromStream(InputStream inputStream) {
		boolean b2 = true;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while (len != -1 && b2) {
			try {
				len = inputStream.read(b);
				if (len != -1) {
					baos.write(b, 0, len);
				}
			} catch (IOException e) {
				b2 = false;
				try {
					inputStream.close();
				} catch (IOException e1) {
				}
			}

		}

		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return baos.toByteArray();
	}

	/*
	 * 判断缓存文件夹是否存在如果存在怎返回文件夹路径,如果不存在新建文件夹并返回文件夹路径
	 */
	private String isCacheFileIsExit() {
		String filePath = "";
		String rootpath = "";

		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			rootpath = Environment.getExternalStorageDirectory().toString();
		}
		filePath = rootpath + CACHE_FILE;
		File file = new File(filePath);
		if (!file.exists()) {
			file.mkdirs();
		}
		return filePath;
	}

	/*
	 * 将url变成图片的地址
	 */
	private String changeUrlToName(String url) {
		String name = url.replaceAll(":", "_");
		name = name.replaceAll("//", "_");
		name = name.replaceAll("/", "_");
		name = name.replaceAll("=", "_");
		name = name.replaceAll(",", "_");
		name = name.replaceAll("&", "_");
		return name;
	}

	public Bitmap put(String key, Bitmap value) {
		String filePath = isCacheFileIsExit();
		String name = changeUrlToName(key);
		File file = new File(filePath, name);
		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(file);
			value.compress(CompressFormat.JPEG, 100, outputStream);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		try {
			if (null != outputStream)
				outputStream.flush();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			if (null != outputStream)
				outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (null != outputStream) {
			try {
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			outputStream = null;
		}

		return super.put(key, value);
	}

	/**
	 * 
	 * @param key
	 * @param value
	 * @param isCacheToLocal
	 *            是否缓存到本地
	 * @return
	 */
	public Bitmap put(String key, Bitmap value, boolean isCacheToLocal) {
		if (isCacheToLocal) {
			return this.put(key, value);
		} else {
			return super.put(key, value);
		}
	}
}

ImageService.java


package com.imageService;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
/**
 * @author jingche.yhq
 使用说明:
	1.先增加权限:
    	<uses-permission android:name="android.permission.INTERNET" />
    	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    2.图片URL和ImageView直接输入函数
    EX:
    	ImageService imageService = new ImageService(this);
    	ImageView imageView;
    	imageService.setBitmapByURL2("http://i1.itc.cn/20120801/a75_b0e447db_3573_ab5c_2058_5845d13545b9_1.jpg", imageView,defaultBitmap);
 */
public class ImageService {
	//*********************************************线程池获取图片资源******************************************************
	//本地数据缓存
	public Map<String, SoftReference<Bitmap>> imageCacheMap = new HashMap<String, SoftReference<Bitmap>>();
	//固定五个线程来执行任务
    private ExecutorService executorService = Executors.newFixedThreadPool(5);
    //回调函数使用

 final static ImageService imageService = new ImageService();
    
	public static ImageService getInstance(){
		return imageService;
	}
	/**
	 * 将图片放进缓存,图片名称是由URL去掉一些符号得到
	 * 
	 * @param url
	 *            地址
	 * @param bitmap
	 *            图片
	 */
	public void putImageCache(String url, Bitmap bitmap) {
		try {
			if(!ImageCache.getInstance().isBitmapExit(url));
				ImageCache.getInstance().put(url, bitmap, true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 
	 * @param url图片URL 
	 * 
	 * @param imageView imageView
	 * 
	 * @param defaultBitmap 获取图片失败这显示默认图片
	 */
	public void setBitmapByURL(String url,final ImageView imageView,final Bitmap defaultBitmap,boolean isCacheToLocal) {
		//采用Handler+Thread+封装外部接口
	    //如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
		Bitmap cacheImage = loadBitmap(url,imageView,isCacheToLocal,new ImageCallback() {
	    //请参见实现:如果第一次加载URL时下面方法会执行
		@Override
		public void imageLoad(ImageView imageView, Bitmap bitmap) {
			//如果返回的Bitmap为空这选择默认图片
	    	   if (bitmap!=null) {
		            imageView.setImageBitmap(bitmap);
	    	   }else {
	    		   imageView.setImageBitmap(defaultBitmap);
	    	   }
		}
	     });
	     if(cacheImage!=null){
	    	 imageView.setImageBitmap(cacheImage);
	     }else {
	    	// imageView.setImageBitmap(defaultBitmap);
		}
	}
	 /**
    *
    * @param imageUrl     图像URL地址
    * @param imageCallback     回调接口
    * @return     返回内存中缓存的图像,第一次加载返回null
    */
   public Bitmap loadBitmap(final String imageUrl,final ImageView imageView,final boolean isCacheToLocal,final ImageCallback imageCallback) {
       //如果缓存过就从缓存中取出数据
	   final Handler handler = new Handler()  
       {  
           @Override  
           public void handleMessage(Message msg)  
           {  
        	   imageCallback.imageLoad(imageView, (Bitmap)msg.obj);  
           }  
       };  
       if (imageCacheMap.containsKey(imageUrl)) {
    	   Log.e("提示", "缓存获取图片");
           SoftReference<Bitmap> softReference = imageCacheMap.get(imageUrl);
           if (softReference.get() != null) {
               return softReference.get();
           }
       }else     
       if(ImageCache.getInstance().isBitmapExit(imageUrl)){
    	   Log.e("提示", "本地获取图片");
    	   Bitmap bitmap=null;
    	   try {
				bitmap = ImageCache.getInstance().get(imageUrl);
			} catch (Exception e) {
				bitmap = null;
			}
			return bitmap;
       }
       else {
		
       //缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中
        executorService.submit(new Runnable() {
           public void run() {
               try {
            	   //获取图片
                   final Bitmap bitmap = getNetBitmapByURL(imageUrl);
                   //将图片放置到内存中
                   Log.e("提示", "网络获取图片"+Thread.currentThread().getName());
                   if(bitmap!=null){
                	   Log.e("提示", "存储图");
                	   imageCacheMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
                	   ImageCache.getInstance().put(imageUrl, bitmap, isCacheToLocal);
                   }
                   Message msg = handler.obtainMessage(0, bitmap);  
                   handler.sendMessage(msg);
               } catch (Exception e) {
                   throw new RuntimeException(e);
               }
           }
       });
       }
       return null;
   }
   //网络获取图片
   protected Bitmap getNetBitmapByURL(String urlString) {
		URL url = null;
		InputStream inputStream = null;
		HttpURLConnection urlConnection = null;
		Bitmap bmp = null;
		try {
			url = new URL(urlString);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.setRequestMethod("GET");
			urlConnection.setConnectTimeout(10000);
			inputStream = urlConnection.getInputStream();
			byte[] bt = getBytesFromStream(inputStream);
			bmp = BitmapFactory.decodeByteArray(bt, 0, bt.length);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != inputStream) {
				try {
					inputStream.close();
					inputStream = null;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != urlConnection) {
				urlConnection.disconnect();
				urlConnection = null;
			}
		}
		return bmp;
	}

	// 数据流
	private byte[] getBytesFromStream(InputStream inputStream) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while (len != -1) {
			try {
				len = inputStream.read(b);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (len != -1) {
				baos.write(b, 0, len); 
			}
		}
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return baos.toByteArray();
	}
   //对外界开放的回调接口
   private interface ImageCallback {
       //注意 此方法是用来设置目标对象的图像资源
	   public void imageLoad(ImageView imageView, Bitmap bitmap);
   }	
   
}


test


public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        ImageService imageService = new ImageService();
        ImageView imageView = (ImageView)findViewById(R.id.imageView1);
       imageService.setBitmapByURL("http://i1.itc.cn/20120801/a75_b0e447db_3573_ab5c_2058_5845d13545b9_1.jpg", imageView,BitmapFactory.decodeResource(getResources(), R.drawable.icon));
    }


呵呵!很多不足,欢迎拍砖哈。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值