1、权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2、视图
1)activity_main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 tools:context=".MainActivity" > 7 8 <ListView 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:id="@+id/lv" 12 /> 13 14 </LinearLayout>
2)lv_item.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <ImageView 7 android:layout_width="wrap_content" 8 android:layout_height="wrap_content" 9 android:id="@+id/iv" 10 /> 11 12 </LinearLayout>
3、MainActivity类
1 package com.zyh.zyh_imageloader; 2 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.view.Menu; 6 import android.widget.ListView; 7 8 public class MainActivity extends Activity { 9 private ListView lv; 10 private final String HOST_PATH = "http://192.168.1.100/android/cache_img/thumb/"; 11 private String[] urls = new String[]{ 12 HOST_PATH + "lmm01.jpg", 13 HOST_PATH + "lmm02.jpg", 14 HOST_PATH + "lmm03.jpg", 15 HOST_PATH + "lmm04.jpg", 16 HOST_PATH + "lmm05.jpg", 17 HOST_PATH + "lmm06.jpg", 18 HOST_PATH + "lmm07.jpg", 19 HOST_PATH + "lmm08.jpg", 20 HOST_PATH + "lmm09.jpg", 21 HOST_PATH + "lmm10.jpg", 22 HOST_PATH + "lmm11.jpg", 23 HOST_PATH + "lmm12.jpg", 24 HOST_PATH + "lmm13.jpg", 25 HOST_PATH + "lmm14.jpg", 26 HOST_PATH + "lmm15.jpg", 27 HOST_PATH + "lmm16.jpg", 28 HOST_PATH + "lmm17.jpg", 29 HOST_PATH + "lmm18.jpg", 30 HOST_PATH + "lmm19.jpg", 31 HOST_PATH + "lmm20.jpg", 32 HOST_PATH + "lmm21.jpg", 33 HOST_PATH + "lmm22.jpg", 34 HOST_PATH + "lmm23.jpg", 35 HOST_PATH + "lmm24.jpg", 36 HOST_PATH + "lmm25.jpg", 37 HOST_PATH + "lmm26.jpg", 38 HOST_PATH + "lmm27.jpg", 39 HOST_PATH + "lmm28.jpg", 40 HOST_PATH + "lmm29.jpg", 41 HOST_PATH + "lmm30.jpg", 42 HOST_PATH + "lmm31.jpg", 43 HOST_PATH + "lmm32.jpg", 44 HOST_PATH + "lmm33.jpg" 45 }; 46 @Override 47 protected void onCreate(Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 setContentView(R.layout.activity_main); 50 51 lv = (ListView) findViewById(R.id.lv); 52 53 lv.setAdapter(new MyAdapter(this,urls)); 54 } 55 56 }
4、MyAdapter
1 package com.zyh.zyh_imageloader; 2 3 import android.content.Context; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.BaseAdapter; 8 import android.widget.ImageView; 9 10 public class MyAdapter extends BaseAdapter { 11 private Context context; 12 private LayoutInflater inflater; 13 private String[] data; 14 private ImageLoader imageLoader; 15 public MyAdapter(Context context, String[] data){ 16 this.context = context; 17 inflater = LayoutInflater.from(this.context); 18 this.data = data; 19 imageLoader = ImageLoader.getInstance(context); 20 } 21 @Override 22 public int getCount() { 23 return data.length; 24 } 25 26 @Override 27 public Object getItem(int position) { 28 return data[position]; 29 } 30 31 @Override 32 public long getItemId(int position) { 33 return position; 34 } 35 36 @Override 37 public View getView(int position, View convertView, ViewGroup parent) { 38 ViewHolder holder = null; 39 if(convertView == null){ 40 holder = new ViewHolder(); 41 convertView = inflater.inflate(R.layout.lv_item, null); 42 ImageView imageView = (ImageView) convertView.findViewById(R.id.iv); 43 holder.imageView = imageView; 44 convertView.setTag(holder); 45 }else{ 46 holder = (ViewHolder) convertView.getTag(); 47 } 48 imageLoader.loadImage(data[position], holder.imageView); 49 50 return convertView; 51 } 52 53 class ViewHolder{ 54 ImageView imageView; 55 } 56 57 }
5、图片缓存构架类(主要类)
1 package com.zyh.zyh_imageloader; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.lang.ref.SoftReference; 10 import java.util.LinkedHashMap; 11 import java.util.concurrent.ConcurrentHashMap; 12 13 import android.content.Context; 14 import android.graphics.Bitmap; 15 import android.graphics.BitmapFactory; 16 import android.graphics.Color; 17 import android.graphics.drawable.ColorDrawable; 18 import android.os.AsyncTask; 19 import android.widget.ImageView; 20 21 public class ImageLoader { 22 private static Context context; 23 private static final int MAX_CAPACITY = 20;//设置强引用的容量 24 private DefaultImage defaultImage = new DefaultImage();//默认ImageView的颜色 25 private static ImageLoader instance = null; 26 27 private ImageLoader(){} 28 //构造函数 29 private ImageLoader(Context context){ 30 this.context = context; 31 } 32 33 //获取对象 34 public static ImageLoader getInstance(Context context){ 35 if(instance == null){ 36 instance = new ImageLoader(context); 37 } 38 return instance; 39 } 40 41 //一级缓存,强引用 42 //0.75f是排序因子;true说明是访问排序;false基于插入排序 43 //LRU最近最少使用算法 44 private static LinkedHashMap<String, Bitmap> firstCacheMap = new LinkedHashMap<String, Bitmap>(MAX_CAPACITY, 0.75f, true){ 45 //根据返回值,移除map中最老的值 46 protected boolean removeEldestEntry(java.util.Map.Entry<String,Bitmap> eldest) { 47 if(this.size() > MAX_CAPACITY){ 48 //加入二级缓存 49 secondCacheMap.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue())); 50 //加入本地缓存 51 diskCache(eldest.getKey(), eldest.getValue()); 52 //移除一级缓存 53 } 54 return false; 55 }; 56 }; 57 58 //二级缓存,软引用 59 //线程安全的 60 private static ConcurrentHashMap<String, SoftReference<Bitmap>> secondCacheMap = new ConcurrentHashMap<String, SoftReference<Bitmap>>(); 61 62 /** 63 * @desc 获取图片,如果从缓存中得不到,则从网络中获取 64 * @param key 65 * @param imageView 66 */ 67 public void loadImage(String key, ImageView imageView){ 68 //从缓存中读取 69 Bitmap bitmap = getFromCache(key); 70 if(bitmap != null){ 71 //结束异步任务 72 //cancelDownload(key, imageView); 73 74 imageView.setImageBitmap(bitmap); 75 }else{ 76 //设置默认图片 77 imageView.setImageDrawable(defaultImage); 78 79 //从网络中读取 80 AsyncImageLoadTast tast = new AsyncImageLoadTast(imageView); 81 tast.execute(key); 82 83 } 84 85 } 86 87 /** 88 * @desc 取消下载 89 * @param key 90 * @param imageView 91 */ 92 private void cancelDownload(String key, ImageView imageView) { 93 //可能有多个异步任务在下载同一张图片 94 AsyncImageLoadTast tast = new AsyncImageLoadTast(imageView); 95 if(tast != null){ 96 String downloadKey = tast.key;//这个key从何而来 97 if(downloadKey == null || downloadKey.equals(key)){ 98 tast.cancel(true); 99 } 100 } 101 } 102 protected static void diskCache(String key, Bitmap value) { 103 //采用md5方式作为图片名称 104 String fileName = MD5Utils.decode(key); 105 String path = context.getCacheDir().getAbsolutePath() + File.separator + fileName; 106 107 //jpg 108 FileOutputStream os = null; 109 try { 110 os = new FileOutputStream(path); 111 value.compress(Bitmap.CompressFormat.JPEG, 100, os); 112 } catch (FileNotFoundException e) { 113 // TODO Auto-generated catch block 114 e.printStackTrace(); 115 }finally{ 116 if(os != null){ 117 try { 118 os.close(); 119 } catch (IOException e) { 120 // TODO Auto-generated catch block 121 e.printStackTrace(); 122 } 123 } 124 } 125 126 } 127 128 class AsyncImageLoadTast extends AsyncTask<String, Void, Bitmap>{ 129 private String key; 130 private ImageView imageView; 131 132 public AsyncImageLoadTast(ImageView imageView) { 133 super(); 134 this.imageView = imageView; 135 } 136 137 @Override 138 protected Bitmap doInBackground(String... params) { 139 key = params[0]; 140 return download(key); 141 } 142 143 @Override 144 protected void onPostExecute(Bitmap result) { 145 super.onPostExecute(result); 146 if(isCancelled()){ 147 result = null; 148 } 149 150 if(result != null){ 151 //添加到一级缓存中去 152 addFirstCache(key, result); 153 //显示 154 imageView.setImageBitmap(result); 155 } 156 } 157 158 159 160 } 161 162 163 private Bitmap getFromCache(String key) { 164 //从一级缓存中获取 165 synchronized(firstCacheMap){ 166 Bitmap bitmap = firstCacheMap.get(key); 167 //为了保持最新使用 168 if(bitmap != null){ 169 firstCacheMap.remove(key);//????不是remove它的key吗? 170 firstCacheMap.put(key, bitmap); 171 return bitmap; 172 } 173 } 174 175 //从二级缓存中获取 176 SoftReference<Bitmap> soft_bitmap = secondCacheMap.get(key); 177 if(soft_bitmap != null){ 178 Bitmap bitmap = soft_bitmap.get(); 179 if(bitmap != null){ 180 //firstCacheMap.put(key, bitmap); 181 addFirstCache(key, bitmap); 182 return bitmap; 183 } 184 }else{ 185 secondCacheMap.remove(key); 186 } 187 188 //从本地获取 189 Bitmap local_bitmap = getFromLocal(key); 190 if(local_bitmap != null){ 191 //firstCacheMap.put(key, local_bitmap); 192 addFirstCache(key, local_bitmap); 193 return local_bitmap; 194 } 195 return null; 196 } 197 198 199 200 201 202 private Bitmap getFromLocal(String key) { 203 String fileName = MD5Utils.decode(key); 204 if(fileName == null){ 205 return null; 206 } 207 208 String path = context.getCacheDir().getAbsolutePath() + File.separator + fileName; 209 210 FileInputStream is = null; 211 try { 212 is = new FileInputStream(path); 213 return BitmapFactory.decodeStream(is); 214 } catch (FileNotFoundException e) { 215 // TODO Auto-generated catch block 216 e.printStackTrace(); 217 }finally{ 218 if(is != null){ 219 try { 220 is.close(); 221 } catch (IOException e) { 222 // TODO Auto-generated catch block 223 e.printStackTrace(); 224 } 225 } 226 } 227 return null; 228 } 229 230 public void addFirstCache(String key, Bitmap bitmap) { 231 if(bitmap != null){ 232 synchronized(firstCacheMap){ 233 firstCacheMap.put(key, bitmap); 234 } 235 } 236 } 237 238 239 240 241 242 public Bitmap download(String key) { 243 InputStream is = null; 244 try { 245 is = HttpUtils.download(key); 246 return BitmapFactory.decodeStream(is); 247 } catch (Exception e) { 248 e.printStackTrace(); 249 }finally{ 250 if(is != null){ 251 try { 252 is.close(); 253 } catch (IOException e) { 254 e.printStackTrace(); 255 } 256 } 257 } 258 return null; 259 } 260 261 class DefaultImage extends ColorDrawable{ 262 public DefaultImage(){ 263 super(Color.BLUE); 264 } 265 } 266 }
6、辅助类
1 package com.zyh.zyh_imageloader; 2 3 import java.io.InputStream; 4 import java.net.HttpURLConnection; 5 import java.net.URL; 6 7 public class HttpUtils { 8 public static InputStream download(String key) throws Exception{ 9 HttpURLConnection conn = (HttpURLConnection) new URL(key).openConnection(); 10 return conn.getInputStream(); 11 } 12 }
1 package com.zyh.zyh_imageloader; 2 3 import java.io.UnsupportedEncodingException; 4 import java.security.MessageDigest; 5 import java.security.NoSuchAlgorithmException; 6 7 public class MD5Utils { 8 public static String decode(String info){ 9 try 10 { 11 MessageDigest md5 = MessageDigest.getInstance("MD5"); 12 md5.update(info.getBytes("UTF-8")); 13 byte[] encryption = md5.digest(); 14 15 StringBuffer strBuf = new StringBuffer(); 16 for (int i = 0; i < encryption.length; i++) 17 { 18 if (Integer.toHexString(0xff & encryption[i]).length() == 1) 19 { 20 strBuf.append("0").append(Integer.toHexString(0xff & encryption[i])); 21 } 22 else 23 { 24 strBuf.append(Integer.toHexString(0xff & encryption[i])); 25 } 26 } 27 28 return strBuf.toString(); 29 } 30 catch (NoSuchAlgorithmException e) 31 { 32 return ""; 33 } 34 catch (UnsupportedEncodingException e) 35 { 36 return ""; 37 } 38 } 39 }
时间: 2024-10-28 04:48:24