最近在学校参加一个比赛,写的一个Android应用,里面要加载大量的网络图片,可是用传统的方法图片一多就会造成程序出现内存溢出而崩溃.因为自己也在学习中,所以看了很多博客和视频,然后参照这些大神的写源码,自己写了一个加载网络图片工具类.
里面要用到一个经典的图片缓存库DiskLruCache 下载地址为:  DiskLruCache下载
下面是使用这个类实现的 双缓存网络图片加载
- public class DiskLruCacheUtils {  
-     private static DiskLruCacheUtils diskLruCacheUtils;  
-   
-     private DiskLruCache diskLruCache; 
-     private LruCache<String, Bitmap> lruCache; 
-   
-     private Context context;  
-   
-     public DiskLruCacheUtils() {  
-     }  
-   
-     public static DiskLruCacheUtils getInstance() {  
-         if (diskLruCacheUtils == null) {  
-             diskLruCacheUtils = new DiskLruCacheUtils();  
-         }  
-         return diskLruCacheUtils;  
-     }  
-   
-   
-     public void open(Context context, String disk_cache_subdir, int disk_cache_size) {  
-         try {  
-             this.context = context;  
-   
-             
-             
-             int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
-             
-             int cacheSize = maxMemory / 8;  
-             lruCache = new LruCache<>(cacheSize);  
-   
-             
-   
-             diskLruCache = DiskLruCache.open(getCacheDir(disk_cache_subdir), getAppVersion(), 1, disk_cache_size);  
-         } catch (IOException e) {  
-             e.printStackTrace();  
-         }  
-     }  
-   
-     
-     public InputStream getDiskCache(String url) {  
-         String key = hashkeyForDisk(url);  
-         try {  
-             DiskLruCache.Snapshot snapshot = diskLruCache.get(key);  
-             if (snapshot != null) {  
-                 return snapshot.getInputStream(0);  
-             }  
-         } catch (IOException e) {  
-             e.printStackTrace();  
-         }  
-         return null;  
-     }  
-   
-   
-     
-     public void putCache(final String url, final CallBack callBack){  
-         new AsyncTask<String,Void,Bitmap>(){  
-   
-             @Override  
-             protected Bitmap doInBackground(String... params) {  
-                 String key = hashkeyForDisk(params[0]);  
-                 DiskLruCache.Editor editor = null;  
-                 Bitmap bitmap = null;  
-   
-                 URL url = null;  
-                 try {  
-                     url = new URL(params[0]);  
-                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
-                     conn.setReadTimeout(30*1000);  
-                     conn.setConnectTimeout(30*1000);  
-                     ByteArrayOutputStream baos = null;  
-   
-                     if (conn.getResponseCode()==HttpURLConnection.HTTP_OK){  
-                         BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());  
-                         baos = new ByteArrayOutputStream();  
-                         byte[] bytes = new byte[1024];  
-                         int len = -1;  
-                         while ((len = bis.read(bytes)) != -1) {  
-                             baos.write(bytes, 0, len);  
-                         }  
-   
-                         bis.close();  
-                         baos.close();  
-                         conn.disconnect();  
-                     }  
-                     if (baos !=null){  
-                         bitmap = decodeSampleadBitmapFromStream(baos.toByteArray(),300,300);  
-                         addBitmapToCache(params[0],bitmap); 
-                         editor = diskLruCache.edit(key); 
-                         
-                         bitmap.compress(Bitmap.CompressFormat.JPEG,30,editor.newOutputStream(0));  
-                         editor.commit();
-                     }  
-   
-   
-                 } catch (Exception e) {  
-                     try {  
-                         editor.abort();
-                     } catch (IOException e1) {  
-                         e1.printStackTrace();  
-                     }  
-                     e.printStackTrace();  
-                 }  
-   
-   
-                 return bitmap;  
-             }  
-   
-             @Override  
-             protected void onPostExecute(Bitmap bitmap) {  
-                 super.onPostExecute(bitmap);  
-                 callBack.response(bitmap);  
-             }  
-         }.execute(url);  
-   
-     }  
-   
-     
-     public void close(){  
-         if (diskLruCache!=null&& !diskLruCache.isClosed()){  
-             try {  
-                 diskLruCache.close();  
-             } catch (IOException e) {  
-                 e.printStackTrace();  
-             }  
-         }  
-     }  
-   
-     
-     public void flush(){  
-         if (diskLruCache!=null){  
-             try {  
-                 diskLruCache.flush();  
-             } catch (IOException e) {  
-                 e.printStackTrace();  
-             }  
-         }  
-     }  
-   
-   
-     
-     public interface  CallBack<T>{  
-         public void response(T entity);  
-     }  
-   
-   
-     
-     public static Bitmap decodeSampleadBitmapFromStream(byte[] bytes, int reqWidth, int reqHeight) {  
-   
-         BitmapFactory.Options options = new BitmapFactory.Options();  
-         options.inJustDecodeBounds = true;
-         BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);  
-         options.inSampleSize = calculatInSampleSize(options, reqWidth, reqHeight);
-         options.inJustDecodeBounds = false;  
-         return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
-     }  
-   
-   
-     
-     public  void addBitmapToCache(String url,Bitmap bitmap){  
-         String key = hashkeyForDisk(url);  
-         if (getBitmapFromMenCache(key)==null){  
-             lruCache.put(key,bitmap);  
-         }  
-     }  
-   
-     
-     public  Bitmap getBitmapFromMenCache(String url){  
-         String key = hashkeyForDisk(url);  
-         return  lruCache.get(key);  
-     }  
-   
-   
-     
-     private static int calculatInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {  
-         
-         final int w = options.outWidth;  
-         final int h = options.outHeight;  
-         int inSampleSize = 1;  
-         
-         if (w > reqWidth || h > reqHeight) {  
-             if (w > h) {  
-                 inSampleSize = Math.round((float) h / (float) reqHeight);  
-             } else {  
-                 inSampleSize = Math.round((float) w / (float) reqWidth);  
-             }  
-         }  
-         return inSampleSize;  
-     }  
-   
-   
-     
-     private String hashkeyForDisk(String key) {  
-         String cachekey;  
-   
-         try {  
-             final MessageDigest mDigest = MessageDigest.getInstance("MD5");  
-             mDigest.update(key.getBytes());  
-             cachekey = bytesToHexString(mDigest.digest());  
-         } catch (NoSuchAlgorithmException e) {  
-             cachekey = String.valueOf(key.hashCode());  
-         }  
-   
-         return cachekey;  
-     }  
-   
-     private String bytesToHexString(byte[] bytes) {  
-         StringBuilder sb = new StringBuilder();  
-         for (int i = 0; i < bytes.length; i++) {  
-             String hex = Integer.toHexString(0xff & bytes[i]);  
-             if (hex.length() == 1) {  
-                 sb.append(0);  
-             }  
-             sb.append(hex);  
-         }  
-         return sb.toString();  
-     }  
-   
-   
-     
-     private File getCacheDir(String name) {  
-         String cachePath = Environment.getExternalStorageState()  
-                 == Environment.MEDIA_MOUNTED || !Environment.isExternalStorageRemovable() ?  
-                 context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();  
-   
-         return new File(cachePath + File.separator + name);  
-     }  
-   
-     
-     private int getAppVersion() {  
-         try {  
-             return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;  
-         } catch (PackageManager.NameNotFoundException e) {  
-             e.printStackTrace();  
-         }  
-         return 1;  
-     }  
- }  
 
 
decodeSampleadBitmapFromStream(byte[] bytes, int reqWidth, int reqHeight)这个函数的实现可以参照 郭大神的博客:Android高效加载大图、多图方案,有效避免程序OOM。
自己也是小白,好多都是复制粘贴,嘿嘿 !  这里就不进行代码的分析了(其实好多我也不懂...),下面就自己上demo把:
现将上面的DiskLruCache,
 在项目中创建一个libcore.io包,将这.jar文件复制进去,然后实现上边的代码(有点多哈!直接复制过去把!). 我这里直接创建了一个DiskLruCacheUtils类里面就是上面的代码! 还是截个图:↓↓↓↓

使用这个工具类的方法:
在你需要的使用这类的Activity 或fragment中,首先:
- private DiskLruCacheUtils diskLruCacheUtils;
- private static final String DISK_CACHE_SUBDIR = "temp"; 
- private static final int DISK_CACHE_SIZE= 100*1024*1024; 
 
然后在他们的声明周期中:
 
- @Override  
-     protected void onResume() {  
-         super.onResume();  
-         diskLruCacheUtils = DiskLruCacheUtils.getInstance();  
-         diskLruCacheUtils.open(this,DISK_CACHE_SUBDIR,DISK_CACHE_SIZE);//打开缓存  
-     }  
-   
-     @Override  
-     protected void onPause() {  
-         super.onPause();  
-         diskLruCacheUtils.flush(); //刷新缓存  
-     }  
-   
-     @Override  
-     protected void onStop() {  
-         super.onStop();  
-         diskLruCacheUtils.close(); //关闭缓存  
-     }  
 
 
加了这代码就可以真正的使用这个工具类了.
但是这样还不行,还得写个图片加载方法:
- private void loadBitmap(String url, final ImageView imageView) {  
-         if (imageView.getTag().equals(url)) {  
-             //从内存缓存中取图片  
-             Bitmap bitmap = diskLruCacheUtils.getBitmapFromMenCache(url);  
-             if (bitmap == null) {  
-                 //如果内存中为空 从磁盘缓存中取  
-                 InputStream in = diskLruCacheUtils.getDiskCache(url);  
-   
-                 if (in == null) {  
-                     //如果缓存中都为空,就通过网络加载,并加入缓存  
-                     diskLruCacheUtils.putCache(url, new DiskLruCacheUtils.CallBack<Bitmap>() {  
-                         @Override  
-                         public void response(Bitmap entity) {  
- //                            System.out.println("网络中下载...");  
-                             imageView.setImageBitmap(entity);  
-                         }  
-                     });  
-                 } else {  
-                     System.out.println("磁盘中取出...");  
-                     bitmap = BitmapFactory.decodeStream(in);  
-                     diskLruCacheUtils.addBitmapToCache(url, bitmap);  
-                     imageView.setImageBitmap(bitmap);  
-                 }  
-             } else {  
- //                System.out.println("内存中取出...");  
-                 imageView.setImageBitmap(bitmap);  
-             }  
-         }  
-     }  
 
然后在你需要加载图片的地方使用该方法就OK, 看起复杂其实还挺简单的  ...(复制过去不就行了...)
直接上Demo:
这是activity_main.xml文件
 
下面上布局文件 挺简单的 RecyclerView+CardView:
- <?xml version="1.0" encoding="utf-8"?>  
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
-     xmlns:tools="http://schemas.android.com/tools"  
-     android:layout_width="match_parent"  
-     android:layout_height="match_parent"  
-     android:paddingBottom="@dimen/activity_vertical_margin"  
-     android:paddingLeft="@dimen/activity_horizontal_margin"  
-     android:paddingRight="@dimen/activity_horizontal_margin"  
-     android:paddingTop="@dimen/activity_vertical_margin"  
-     tools:context="zhengliang.com.bitmaplrucache.MainActivity">  
-   
-     <android.support.v7.widget.RecyclerView  
-         android:layout_width="match_parent"  
-         android:layout_height="match_parent"  
-         android:id="@+id/rlv_list"  
-         >  
-     </android.support.v7.widget.RecyclerView>  
- </RelativeLayout>  
 
挺简单的就一个 RecyclerView 因为要加载很多图片所以就用这个了,(哈哈! 我喜欢他的瀑布流! 爽到爆炸啊...)
这是item.xml文件
 
- <?xml version="1.0" encoding="utf-8"?>  
- <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"  
-     xmlns:app="http://schemas.android.com/apk/res-auto"  
-     android:layout_width="wrap_content"  
-     android:layout_height="wrap_content"  
-     android:layout_margin="2dp"  
-     app:cardBackgroundColor="@color/colorAccent"  
-     app:cardCornerRadius="2dp"  
-     android:background="@color/colorAccent"  
-     >  
-   
-     <ImageView  
-         android:id="@+id/pic"  
-         android:layout_width="match_parent"  
-         android:layout_height="wrap_content"  
-         android:scaleType="centerCrop"  
-         />  
-   
- </android.support.v7.widget.CardView>  
 
就一个CardView ,里面放了一个ImageView 
MainActivity类中代码如下:
      
因为这里没有图片资源所以自己用Volley框架写了一个获取图片资源的getImageUrl()方法里面返回一些图片资源的URL地址  
(找图片真的很恼火啊,一条一条的把图片地址复制过来不是我的风范啊! 就在百度图片中经过千辛万苦扒了个图片API接口下来,哈哈 有图片咯!)
 
- <pre name="code" class="java">public class MainActivity extends AppCompatActivity{  
-   
-   
-     private List<String> data;  
-     private DiskLruCacheUtils diskLruCacheUtils;  
-     private static final String DISK_CACHE_SUBDIR = "temp";  
-     private static final int DISK_CACHE_SIZE= 100*1024*1024;  
-     private RecyclerView rlvlist;  
-   
-     private MyAdapter myAdapter;  
-   
-   
-     @Override  
-     protected void onCreate(Bundle savedInstanceState) {  
-         super.onCreate(savedInstanceState);  
-         setContentView(R.layout.activity_main);  
-         initViews();  
-         getImageUrl("http://image.baidu.com/channel/listjson?pn=0&rn=200&tag1=美女&tag2=小清新&ie=utf8");  
-     }  
-   
-   
-     private void initViews() {  
-         data = new ArrayList<String>();  
-         this.rlvlist = (RecyclerView) findViewById(R.id.rlv_list);  
-         rlvlist.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));  
-     }  
-   
-     @Override  
-     protected void onResume() {  
-         super.onResume();  
-         diskLruCacheUtils = DiskLruCacheUtils.getInstance();  
-         diskLruCacheUtils.open(this,DISK_CACHE_SUBDIR,DISK_CACHE_SIZE);  
-     }  
-   
-     @Override  
-     protected void onPause() {  
-         super.onPause();  
-         diskLruCacheUtils.flush();  
-     }  
-   
-     @Override  
-     protected void onStop() {  
-         super.onStop();  
-         diskLruCacheUtils.close();  
-     }  
-   
-     public void getImageUrl(String url){  
-   
-         final RequestQueue mQueue = Volley.newRequestQueue(this);  
-   
-         JsonObjectRequest stringRequest = new JsonObjectRequest(url, null,  
-                 new Response.Listener<JSONObject>() {  
-                     @Override  
-                     public void onResponse(JSONObject jsonObject) {  
-                         try {  
-                             JSONArray jsonArray = jsonObject.getJSONArray("data");  
-                             for (int i = 0; i <jsonArray.length() ; i++) {  
-                                 JSONObject item = jsonArray.getJSONObject(i);  
-                                 String url = item.getString("image_url");  
-                                 String name = item.getString("tags");  
-                                 data.add(url);  
-   
-                                 myAdapter = new MyAdapter(data,MainActivity.this,diskLruCacheUtils);  
-                                 rlvlist.setAdapter(myAdapter);  
-                                 myAdapter.notifyDataSetChanged();  
-                             }  
-                         } catch (JSONException e) {  
-                             e.printStackTrace();  
-                         }  
-                     }  
-                 }, new Response.ErrorListener() {  
-             @Override  
-             public void onErrorResponse(VolleyError volleyError) {  
-   
-             }  
-         }  
-         );  
-   
-         mQueue.add(stringRequest);  
-   
-         if (data.size()==200){  
-             getImageUrl("http://image.baidu.com/channel/listjson?pn=0&rn=200&tag1=美女&tag2=全部&ie=utf8");  
-         }  
-   
-     }  
-     public void getImageUrl2(String url){  
-   
-         final RequestQueue mQueue = Volley.newRequestQueue(this);  
-   
-         JsonObjectRequest stringRequest = new JsonObjectRequest(url, null,  
-                 new Response.Listener<JSONObject>() {  
-                     @Override  
-                     public void onResponse(JSONObject jsonObject) {  
-                         try {  
-                             JSONArray jsonArray = jsonObject.getJSONArray("imgs");  
-                             for (int i = 0; i <jsonArray.length() ; i++) {  
-                                 JSONObject item = jsonArray.getJSONObject(i);  
-                                 String url = item.getString("hoverURL");  
-                                 String name = item.getString("fromPageTitle");  
-                                 data.add(url);  
-   
-                                 myAdapter = new MyAdapter(data,MainActivity.this,diskLruCacheUtils);  
-                                 rlvlist.setAdapter(myAdapter);  
-                                 myAdapter.notifyDataSetChanged();  
-                             }  
-                         } catch (JSONException e) {  
-                             e.printStackTrace();  
-                         }  
-                     }  
-                 }, new Response.ErrorListener() {  
-             @Override  
-             public void onErrorResponse(VolleyError volleyError) {  
-   
-             }  
-         }  
-         );  
-   
-         mQueue.add(stringRequest);  
-   
-   
-     }  
-   
-   
-   
- }  
 
   然后是就是实现RecyclerView 的Adapter,因为网络图片的加载都要在Adapter中,所以loadBitmap()方法我就直接写在这里了  废话少说直接上代码
 
- public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {  
-   
-     private List<String> list;  
-     private Context context;  
-     private DiskLruCacheUtils diskLruCacheUtils;  
-   
-     public MyAdapter(List<String> list, Context context, DiskLruCacheUtils diskLruCacheUtils) {  
-         this.list = list;  
-         this.context = context;  
-         this.diskLruCacheUtils = diskLruCacheUtils;  
-     }  
-   
-     @Override  
-     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
-   
-         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view,parent,false);  
-         return new ViewHolder(view);  
-     }  
-   
-     @Override  
-     public void onBindViewHolder(ViewHolder holder, int position) {  
-         holder.pic.setTag(list.get(position));  
-         loadBitmap(list.get(position),holder.pic);  
-         System.out.println(position);  
-     }  
-   
-     @Override  
-     public int getItemCount() {  
-         return list==null?0:list.size();  
-     }  
-   
-     public static class ViewHolder extends RecyclerView.ViewHolder {  
-   
-         public ImageView pic;  
-   
-         public ViewHolder(View itemView) {  
-             super(itemView);  
-             pic = (ImageView) itemView.findViewById(R.id.pic);  
-   
-         }  
-     }  
-   
-     private void loadBitmap(String url, final ImageView imageView) {  
-         if (imageView.getTag().equals(url)) {  
-             
-             Bitmap bitmap = diskLruCacheUtils.getBitmapFromMenCache(url);  
-             if (bitmap == null) {  
-                 
-                 InputStream in = diskLruCacheUtils.getDiskCache(url);  
-   
-                 if (in == null) {  
-                     
-                     diskLruCacheUtils.putCache(url, new DiskLruCacheUtils.CallBack<Bitmap>() {  
-                         @Override  
-                         public void response(Bitmap entity) {  
-                             imageView.setImageBitmap(entity);  
-                         }  
-                     });  
-                 } else {  
-                     System.out.println("磁盘中取出...");  
-                     bitmap = BitmapFactory.decodeStream(in);  
-                     diskLruCacheUtils.addBitmapToCache(url, bitmap);  
-                     imageView.setImageBitmap(bitmap);  
-                 }  
-             } else {  
-                 imageView.setImageBitmap(bitmap);  
-             }  
-         }  
-     }  
-   
- }  
 
 
大工告成 看看效果
     第一进入时全是从 显示"网络中下载..."  因为RecyclerView和ListView一样,超出屏幕的Item都会被回收,当再次滑动回到上次的位置就会重新获取item,并且会重新获取图片,.
   下面看看滑动回去打印的log 
      全是显示从内存中取出,并没有再重网络中下载,说明刚才的图片都缓存到内存中了,这样就加快的图片的显示,还节省了流量!(这年头流量伤不起啊!)
下面再看看关闭应用再打开是什么效果吧!
        全部显示的是从磁盘中取出... 因为关闭应用,这个时候内存中缓存的图片就会被清空. 这个时候就会自动看SD中是否有缓存了. 并且从SD中取出的图片会再一次缓存到内存中去...我这里是加载的200张图片,完全没有问题,嘿嘿...
Android中用双缓存技术,加载网络图片
原文:http://www.cnblogs.com/yukewei/p/5788852.html