public class PhotoWallAdapter extends ArrayAdapter implementsOnScrollListener {/*** 记录所有正在下载或等待下载的任务。*/
private SettaskCollection;/*** 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。*/
private LruCachemMemoryCache;/*** GridView的实例*/
privateGridView mPhotoWall;/*** 第一张可见图片的下标*/
private intmFirstVisibleItem;/*** 一屏有多少张图片可见*/
private intmVisibleItemCount;/*** 记录是否刚打开程序,用于解决进入程序不滚动屏幕,不会下载图片的问题。*/
private boolean isFirstEnter = true;public PhotoWallAdapter(Context context, inttextViewResourceId, String[] objects,
GridView photoWall) {super(context, textViewResourceId, objects);
mPhotoWall=photoWall;
taskCollection= new HashSet();//获取应用程序最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();int cacheSize = maxMemory / 8;//设置图片缓存大小为程序最大可用内存的1/8
mMemoryCache = new LruCache(cacheSize) {
@Overrideprotected intsizeOf(String key, Bitmap bitmap) {returnbitmap.getByteCount();
}
};
mPhotoWall.setOnScrollListener(this);
}
@Overridepublic View getView(intposition, View convertView, ViewGroup parent) {final String url =getItem(position);
View view;if (convertView == null) {
view= LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);
}else{
view=convertView;
}final ImageView photo =(ImageView) view.findViewById(R.id.photo);//给ImageView设置一个Tag,保证异步加载图片时不会乱序
photo.setTag(url);
setImageView(url, photo);returnview;
}/*** 给ImageView设置图片。首先从LruCache中取出图片的缓存,设置到ImageView上。如果LruCache中没有该图片的缓存,
* 就给ImageView设置一张默认图片。
*
*@paramimageUrl
* 图片的URL地址,用于作为LruCache的键。
*@paramimageView
* 用于显示图片的控件。*/
private voidsetImageView(String imageUrl, ImageView imageView) {
Bitmap bitmap=getBitmapFromMemoryCache(imageUrl);if (bitmap != null) {
imageView.setImageBitmap(bitmap);
}else{
imageView.setImageResource(R.drawable.empty_photo);
}
}/*** 将一张图片存储到LruCache中。
*
*@paramkey
* LruCache的键,这里传入图片的URL地址。
*@parambitmap
* LruCache的键,这里传入从网络上下载的Bitmap对象。*/
public voidaddBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemoryCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}/*** 从LruCache中获取一张图片,如果不存在就返回null。
*
*@paramkey
* LruCache的键,这里传入图片的URL地址。
*@return对应传入键的Bitmap对象,或者null。*/
publicBitmap getBitmapFromMemoryCache(String key) {returnmMemoryCache.get(key);
}
@Overridepublic void onScrollStateChanged(AbsListView view, intscrollState) {//仅当GridView静止时才去下载图片,GridView滑动时取消所有正在下载的任务
if (scrollState ==SCROLL_STATE_IDLE) {
loadBitmaps(mFirstVisibleItem, mVisibleItemCount);
}else{
cancelAllTasks();
}
}
@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, intvisibleItemCount,inttotalItemCount) {
mFirstVisibleItem=firstVisibleItem;
mVisibleItemCount=visibleItemCount;//下载的任务应该由onScrollStateChanged里调用,但首次进入程序时onScrollStateChanged并不会调用,//因此在这里为首次进入程序开启下载任务。
if (isFirstEnter && visibleItemCount > 0) {
loadBitmaps(firstVisibleItem, visibleItemCount);
isFirstEnter= false;
}
}/*** 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象,
* 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。
*
*@paramfirstVisibleItem
* 第一个可见的ImageView的下标
*@paramvisibleItemCount
* 屏幕中总共可见的元素数*/
private void loadBitmaps(int firstVisibleItem, intvisibleItemCount) {try{for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
String imageUrl=Images.imageThumbUrls[i];
Bitmap bitmap=getBitmapFromMemoryCache(imageUrl);if (bitmap == null) {
BitmapWorkerTask task= newBitmapWorkerTask();
taskCollection.add(task);
task.execute(imageUrl);
}else{
ImageView imageView=(ImageView) mPhotoWall.findViewWithTag(imageUrl);if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}/*** 取消所有正在下载或等待下载的任务。*/
public voidcancelAllTasks() {if (taskCollection != null) {for(BitmapWorkerTask task : taskCollection) {
task.cancel(false);
}
}
}/*** 异步下载图片的任务。
*
*@authorguolin*/
class BitmapWorkerTask extends AsyncTask{/*** 图片的URL地址*/
privateString imageUrl;
@OverrideprotectedBitmap doInBackground(String... params) {
imageUrl= params[0];//在后台开始下载图片
Bitmap bitmap = downloadBitmap(params[0]);if (bitmap != null) {//图片下载完成后缓存到LrcCache中
addBitmapToMemoryCache(params[0], bitmap);
}returnbitmap;
}
@Overrideprotected voidonPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);//根据Tag找到相应的ImageView控件,将下载好的图片显示出来。
ImageView imageView =(ImageView) mPhotoWall.findViewWithTag(imageUrl);if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
taskCollection.remove(this);
}/*** 建立HTTP请求,并获取Bitmap对象。
*
*@paramimageUrl
* 图片的URL地址
*@return解析后的Bitmap对象*/
privateBitmap downloadBitmap(String imageUrl) {
Bitmap bitmap= null;
HttpURLConnection con= null;try{
URL url= newURL(imageUrl);
con=(HttpURLConnection) url.openConnection();
con.setConnectTimeout(5 * 1000);
con.setReadTimeout(10 * 1000);
bitmap=BitmapFactory.decodeStream(con.getInputStream());
}catch(Exception e) {
e.printStackTrace();
}finally{if (con != null) {
con.disconnect();
}
}returnbitmap;
}
}
}