写的一个图片缓存的demo,包括内存缓存和硬盘缓存,加载大量图片的时候感觉效果还是挺好的。
直接上代码吧:
package com.; import android.os.Bundle; import android.; import android.; import android.; import android.; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.; import com.; import com.; import com.; /** * @author:zhongyao on 2016/7/22 10:52 * @description:网络加载图片性能测试 */ public class DetailLoadPicsTestFragment extends Fragment{ private static DetailLoadPicsTestFragment loadPicsTestFragment; private RecyclerView rv; private DetailLoadPicsTestAdapter mAdapter; private DetailLoadPicsTestFragment(){} @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = in); initView(view); return view; } private void initView(View view) { rv = (RecyclerView) view.findViewById); rv.setLayoutManager(new GridLayoutManager(getActivity(), APPCon)); mAdapter = new DetailLoadPicsTestAdapter(getActivity(), Da()); rv.setAdapter(mAdapter); } public static Fragment newInstance() { if (loadPicsTestFragment == null){ synchronized ){ if (loadPicsTestFragment == null){ loadPicsTestFragment = new DetailLoadPicsTestFragment(); } } } return loadPicsTestFragment; } } package com.; import android.con; import android.gra; import android.os.Handler; import android.; import android..ViewHolder; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.; import com.; import com.; import com.; import com.; import com.; import com.; import java.u; /** * @author:zhongyao on 2016/7/22 11:09 * @description: */ public class DetailLoadPicsTestAdapter extends RecyclerView.Adapter<De; { private Context context; private ArrayList<String> imageUrls; private LayoutInflater inflater; private Handler mHandler = new Handler(); public DetailLoadPicsTestAdapter(Context context, ArrayList<String> imageUrls) { = context; this.imageUrls = imageUrls; = Layou(context); } @Override public LoadPicsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = in, parent, false); return new LoadPicsViewHolder(view); } @Override public void onBindViewHolder(final LoadPicsViewHolder holder, final int position) { /** * 使用自己写的内存缓存+SD卡缓存(貌似效果甚至比使用DiskLruCache的效果好,这就比较蛋疼了,没看出DiskLruCache的优点) */ ImageWorker.loadImage(holder.iv,imageUrls.get(position) ,mHandler); } @Override public int getItemCount() { return imageUrls.size(); } public class LoadPicsViewHolder extends ViewHolder { private ImageView iv; public LoadPicsViewHolder(View itemView) { super(itemView); iv = (ImageView) i); } }
}
以上就是使用RecyclerView实现的GridView,真正加载缓存图片的是:ImageWorker.loadImage(holder.iv,imageUrls.get(position),mHandler);这行代码。
下面我们着重介绍ImageWorker等类,内存缓存用的是LruCache类,sd卡缓存是自己写的,测试效果貌似不比用DiskLruCache差。(最后我会给出demo,demo中也用到了DiskLruCache做对比,有兴趣的可以自己测试下性能,对比下,欢迎交流)。
package com.; import android.gra; import android.graFactory; import android.os.Environment; import android.os.Handler; import android.; import android.widget.ImageView; import com.; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.u; import java.u; /** * 图片缓存类ImageWorker: * 与ImageTask类相似 */ public class ImageWorker { private static final int lruSizeMaxSize = 10*1024*1024;// 图片内存缓存最大空间10M public final static LruCache<String,Bitmap> mLruCache = new LruCache<String,Bitmap>(lruSizeMaxSize); private static ExecutorService mExecutorService = null;// 下载图片的线程管理类 private static final int threadPoolMaxSize = 6;// 同时下载图片的 最大线程数 private ImageWorker() { } private static ImageWorker mImageWorker = null; private static String bitmapPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/zhong/";// 图片在硬盘中的存储地址 /** * 初始化,使用单例获得ImageWorker1的对象 */ public static synchronized ImageWorker getImageWorkerInstance(){ if(mImageWorker == null){ mImageWorker = new ImageWorker(); mExecutorService = Execu(threadPoolMaxSize); } return mImageWorker; } /** * (简单来说)加载图片: * 1 先从内存缓存中查找,如果没有则执行下一步。 * 2 从磁盘中查找,如果没有执行下一步。 * 3从网络下载 */ /** * 1、首先判断内存缓存是否为空(不为空直接显示) * 2、内存缓存为空时,再从磁盘中读取后,将图片添加到内存缓存中(然后显示) * 3、磁盘为空时,只能重新网络加载图片(下载下来的图片,会在内存缓存、磁盘中各存储一份,然后显示) * @param mImageView * @param imgUrl * @param mHandler */ public static void loadImage(ImageView mImageView, String imgUrl, Handler mHandler) { getImageWorkerInstance(); Bitmap bitmapCache = getBitmapFromCache(imgUrl); if(bitmapCache!=null){ mImageView.setImageBitmap(bitmapCache); }else { Bitmap bitmapDisk = getBitmapFromDisk(imgUrl); if(bitmapDisk!=null){ addBitmapToLruCache(imgUrl,bitmapDisk); mImageView.setImageBitmap(bitmapDisk); }else{ loadImageFromNetwork(mImageView,imgUrl,mHandler,mLruCache,bitmapPath); } } } private static void loadImageFromNetwork(ImageView mImageView, String imgUrl, Handler mHandler, LruCache<String, Bitmap> mLruCache, String bitmapPath) { mExecu(new DownloadImageFromNetwork(mImageView,imgUrl,mHandler,mLruCache,bitmapPath)); } private static void addBitmapToLruCache(String imgUrl, Bitmap bitmapDisk) { mLruCac(imgUrl,bitmapDisk); } private static Bitmap getBitmapFromDisk(String imgUrl) { InputStream inputStream = null; String[] fileNames = imgUrl.split("/"); String fileName = fileNames[]; try { inputStream = new FileInputStream(bitmapPath+fileName); } catch (FileNotFoundException e) { e.printStackTrace(); } Bitmap bitmap = Bi(inputStream); return bitmap; } /** * 第一步:尝试从缓存中获取图片 * @param imgUrl * @return */ private static Bitmap getBitmapFromCache(String imgUrl) { Bitmap bitmap = mLruCac(imgUrl); return bitmap; } }
说的很清晰了,还是那一套:先内存找,没有则sd,sd没有,则网络加载。
这里用到了ExecutorService线程管理类,可以设置启动最大的线程数,线程对象可重复利用,避免过多的重复创建线程对象,浪费内存空间。
package com.; import android.gra; import android.graFactory; import android.os.Handler; import android.; import android.widget.ImageView; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; /** * @author:zhongyao on 2016/7/11 10:39 * @description:从网络下载图片,并将下载好的图片存储到内存缓存、SD卡缓存中 */ public class DownloadImageFromNetwork implements Runnable { private ImageView mImageView; private String imgUrl; private Handler mHandler; private LruCache<String, Bitmap> mLruCache; private String bitmapPath; public DownloadImageFromNetwork(ImageView mImageView, String imgUrl, Handler mHandler, LruCache<String, Bitmap> mLruCache, String bitmapPath) { = mImageView; = imgUrl; = mHandler; = mLruCache; = bitmapPath; } @Override public void run() { try { InputStream inputStream; URL url = new URL(imgUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(10 * 1000); conn.setConnectTimeout(10 * 1000); conn.setDoInput(true); conn.connect();// Starts the query int responseCode = conn.getResponseCode(); if (responseCode == 200) { inputStream = conn.getInputStream(); if (inputStream != null) { final Bitmap bitmapNetwork = Bi(inputStream); mHandler.post(new Runnable() { @Override public void run() { mImageView.setImageBitmap(bitmapNetwork); } }); /** * 此时输入流inputStream不存在了(输入流使用一次后就没有了), * 所以以下两行传送的代码是Bitmap对象 */ addBitmapToCache(imgUrl, bitmapNetwork); addBitmapToDisk(imgUrl, bitmapNetwork); } } } catch (Exception e) { e.printStackTrace(); } } private void addBitmapToDisk(String imgUrl, Bitmap bitmapNetwork) { OutputStream outputStream = null; BufferedOutputStream bos = null; InputStream inputStream = null; File file = new File(bitmapPath); if (!()) { boolean result = (); } try { String[] fileNames = imgUrl.split("/"); String fileName = fileNames[ - 1]; outputStream = new FileOutputStream(bitmapPath + fileName); bos = new BufferedOutputStream(outputStream); /** * 以下三行的代码表示: * 将Bitmap对象转换为inputStream */ ByteArrayOutputStream baos = new ByteArrayOutputStream(); bi, 100, baos); inputStream = new ByteArrayInputStream()); byte[] data = new byte[1024]; while (data) != -1) { bos.write(data); } } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); ou(); in(); } catch (Exception e) { e.printStackTrace(); } } } private void addBitmapToCache(String imgUrl, Bitmap bitmapNetwork) { mLruCac(imgUrl, bitmapNetwork); } }
该类需要注意的是,下载完图片并展示的时候,需要将其加载到内存和sd卡缓存中。以后再次加载的时候直接get就可以了。
效果图:
原文链接: