一、首先,废话不多说,先上图片

二、实现思路

1、缓存在本地和内存中,每次加载都从本地中读取,如果本地没有则从网络下载,并保存到本地或者内存

2、内存缓存使用软引用和LruCache算法

3、本地缓存使用DiskLruCache算法

4、LruCache算法系统自带,DiskLruCache算法如果没有可以去网上下载,当然最后我会在我的资源里放上源码

三、实现

1、创建文件目录

2、先创建图片缓存接口 BitmapCache且实现该接口

public interface BitmapCache {/*** 缓存bitmap* @param request* @param bitmap*/void put(BitmapRequest request, Bitmap bitmap);/*** 通过请求去bitmap* @param request* @return*/Bitmap get(BitmapRequest request);/*** 移除bitmap* @param request*/void remove(BitmapRequest request);
}
本地缓存实现 DiskCache.java
public class DiskCache implements BitmapCache {private static DiskCache mDiskCache;//缓存路径 ,这里可以换成你想要保存的名字和路径private String mCacheDir = "testImage";//MBprivate static final int MB = 1024 * 1024;private DiskLruCache mDiskLruCache;public DiskCache(Context context) {initDiskCache(context);}public static DiskCache getInstance(Context context) {if (mDiskCache == null) {synchronized (DiskCache.class) {if (mDiskCache == null) {mDiskCache = new DiskCache(context);}}}return mDiskCache;}private void initDiskCache(Context context) {//得到缓存的目录 data/data目录下,好处,app卸载后,文件自动被删除File directory = getDiskCacheDir(mCacheDir, context);if (!directory.exists()) {directory.mkdirs();}try {//mxSize 指定缓存容量mDiskLruCache = DiskLruCache.open(directory, 1, 1, 50 * MB);} catch (IOException e) {e.printStackTrace();}}private File getDiskCacheDir(String mCacheDir, Context context) {File cacheDir = context.getCacheDir();File newCacheDir = new File(cacheDir, mCacheDir);Log.i("wxf", "new cache path:" + newCacheDir.getAbsolutePath());return newCacheDir;}@Overridepublic void put(BitmapRequest request, Bitmap bitmap) {DiskLruCache.Editor editor = null;OutputStream os = null;try {//路径必须是合法字符editor = mDiskLruCache.edit(request.getImageUriMD5());os = editor.newOutputStream(0);if (os != null) {if (persistBitmap2Disk(bitmap, os)) {editor.commit();} else {editor.abort();}}} catch (IOException e) {e.printStackTrace();}}private boolean persistBitmap2Disk(Bitmap bitmap, OutputStream os) {
//图片质量压缩BufferedOutputStream bos = new BufferedOutputStream(os);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);try {bos.flush();} catch (IOException e) {e.printStackTrace();return false;} finally {IOUtil.closeQuietly(bos);}return true;}@Overridepublic Bitmap get(BitmapRequest request) {try {DiskLruCache.Snapshot snapshot = mDiskLruCache.get(request.getImageUriMD5());if (snapshot != null) {InputStream inputStream = snapshot.getInputStream(0);return BitmapFactory.decodeStream(inputStream);}} catch (IOException e) {e.printStackTrace();}return null;}@Overridepublic void remove(BitmapRequest request) {try {mDiskLruCache.remove(request.getImageUriMD5());} catch (IOException e) {e.printStackTrace();}}
}
内存缓存实现 MemoryCache.java
public class MemoryCache implements BitmapCache {private LruCache<String, Bitmap> mLruCache;public MemoryCache() {int maxSize = (int) (Runtime.getRuntime().freeMemory() / 1024 / 8);mLruCache = new LruCache<String, Bitmap>(maxSize) {@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getRowBytes() * value.getHeight();}};}@Overridepublic void put(BitmapRequest request, Bitmap bitmap) {mLruCache.put(request.getImageUriMD5(), bitmap);}@Overridepublic Bitmap get(BitmapRequest request) {return mLruCache.get(request.getImageUriMD5());}@Overridepublic void remove(BitmapRequest request) {mLruCache.remove(request.getImageUriMD5());}
}

缓存调用 DoubleCache.java

public class DoubleCache implements BitmapCache {//内存缓存private MemoryCache mMemoryCache = new MemoryCache();// 硬盘缓存private DiskCache mDiskCache;public DoubleCache(Context context) {mDiskCache = DiskCache.getInstance(context);}@Overridepublic void put(BitmapRequest request, Bitmap bitmap) {mMemoryCache.put(request, bitmap);mDiskCache.put(request, bitmap);}@Overridepublic Bitmap get(BitmapRequest request) {Bitmap bitmap = mMemoryCache.get(request);if (bitmap == null) {bitmap = mDiskCache.get(request);if (bitmap != null) {//放入内存,方便获取mMemoryCache.put(request, bitmap);}}return bitmap;}@Overridepublic void remove(BitmapRequest request) {mMemoryCache.remove(request);mDiskCache.remove(request);}
}

3、设置加载中和加载失败的默认图片 Displayconfig.java

public class Displayconfig {/*** 加载过程中默认显示的图片Id*/public int loadingImage = -1;/*** 加载失败显示的图片*/public int failImage = -1;}

4、图片加载配置  ImageLoaderConfig.java

public class ImageLoaderConfig {//缓存策略private BitmapCache bitmapCache=new MemoryCache();//加载策略private LoadPolicy loadPolicy=new ReversePolicy();//默认加载线程数private int threadcount = Runtime.getRuntime().availableProcessors();//显示配置private Displayconfig displayconfig=new Displayconfig();private ImageLoaderConfig() {}/*** 建造者模式*/public static class Builder {private ImageLoaderConfig config;public Builder() {this.config = new ImageLoaderConfig();}/*** 设置缓存策略** @param bitmapCache* @return*/public Builder setCachePlicy(BitmapCache bitmapCache) {this.config.bitmapCache = bitmapCache;return this;}/*** 设置加载策略** @param loadpolicy* @return*/public Builder setLoadpolicy(LoadPolicy loadpolicy) {this.config.loadPolicy = loadpolicy;return this;}/*** 设置线程数量** @param threadCount* @return*/public Builder setThreadCount(int threadCount) {this.config.threadcount = threadCount;return this;}/**** 设置加载过程中的图片* @param ResID* @return*/public Builder setLoadingImage(int ResID) {this.config.displayconfig.loadingImage = ResID;return this;}/*** 设置加载失败的图片** @param ResID* @return*/public Builder setFailImage(int ResID) {this.config.displayconfig.failImage = ResID;return this;}public ImageLoaderConfig build(){return this.config;}}public BitmapCache getBitmapCache() {return bitmapCache;}public LoadPolicy getLoadPolicy() {return loadPolicy;}public int getThreadcount() {return threadcount;}public Displayconfig getDisplayconfig() {return displayconfig;}
}

5、创建加载接口  Loader.java

public interface Loader {/*** 加载图片** @param request*/void loadImage(BitmapRequest request);
}

实现图片的加载类以实现控制图片加载 SimpleImageLoader.java

public class SimpleImageLoader {/*** 配置文件*/private ImageLoaderConfig config;/*** 请求队列*/private RequestQueue mRequestQueue;/*** 单例对象*/private static volatile SimpleImageLoader mInstance;private SimpleImageLoader() {}private SimpleImageLoader(ImageLoaderConfig imageLoaderConfig) {this.config = imageLoaderConfig;mRequestQueue = new RequestQueue(config.getThreadcount());//开启队列mRequestQueue.start();}/*** 获取单例方法** @param config* @return*/public static SimpleImageLoader getInstance(ImageLoaderConfig config) {if (mInstance == null) {synchronized (SimpleImageLoader.class) {if (mInstance == null) {mInstance = new SimpleImageLoader(config);}}}return mInstance;}/*** 第二次获取单例** @return*/public static SimpleImageLoader getInstance() {if (mInstance == null) {throw new UnsupportedOperationException("没有初始化");}return mInstance;}/*** @param imageView* @param uri       file开头*/public void displayImage(ImageView imageView, String uri) {displayImage(imageView, uri, null, null);}public void displayImage(ImageView imageView, String uri, Displayconfig displayconfig, ImageListener imageListener) {//实例化一个请求BitmapRequest bitmapRequest = new BitmapRequest(imageView, uri, displayconfig, imageListener);
//        添加到队列里边去mRequestQueue.addRequest(bitmapRequest);}public static interface ImageListener {void onComplete(ImageView imageView, Bitmap bitmap, String uri);}/*** 获取到全局配置** @return*/public ImageLoaderConfig getConfig() {return config;}
}

实现Loader加载逻辑 AbstarctLoader.java

public abstract class AbstarctLoader implements Loader {//拿到用户自定义配置的缓存策略private BitmapCache bitmapCache = SimpleImageLoader.getInstance().getConfig().getBitmapCache();//拿到显示配置private Displayconfig displayConfig = SimpleImageLoader.getInstance().getConfig().getDisplayconfig();@Overridepublic void loadImage(BitmapRequest request) {//从缓存中取到bitmapBitmap bitmap = bitmapCache.get(request);if (bitmap == null) {//显示默认加载图片showLoadingImage(request);//开始真正加载图片bitmap = onLoad(request);//缓存图片cacheBitmap(request, bitmap);}deliveryToUIThread(request,bitmap);}/*** 交给主线程显示* @param request* @param bitmap*/protected void deliveryToUIThread(final BitmapRequest request, final Bitmap bitmap) {ImageView imageView = request.getImageView();if(imageView!=null){imageView.post(new Runnable() {@Overridepublic void run() {updateImageView(request, bitmap);}});}}private void updateImageView(final BitmapRequest request, final Bitmap bitmap) {ImageView imageView = request.getImageView();//加载正常  防止图片错位if(bitmap != null && imageView.getTag().equals(request.getImageUrl())){imageView.setImageBitmap(bitmap);}//有可能加载失败if(bitmap == null && request.getDisplayConfig()!=null&&request.getDisplayConfig().failImage!=-1){imageView.setImageResource(displayConfig.failImage);}//监听//回调 给圆角图片  特殊图片进行扩展if(request.imageListener != null){request.imageListener.onComplete(imageView, bitmap, request.getImageUrl());}}private void cacheBitmap(BitmapRequest request, Bitmap bitmap) {if (request != null && bitmap != null) {synchronized (AbstarctLoader.class) {bitmapCache.put(request, bitmap);}}}//抽象加载策略,因为加载网络图片和本地图片有差异protected abstract Bitmap onLoad(BitmapRequest request);private void showLoadingImage(BitmapRequest request) {//指定了,显示配置if (hasLoadingPlaceHolder()) {final ImageView imageView = request.getImageView();if (imageView != null) {imageView.post(new Runnable() {@Overridepublic void run() {imageView.setImageResource(displayConfig.loadingImage);}});}}}protected boolean hasLoadingPlaceHolder() {return (displayConfig != null && displayConfig.loadingImage > 0);}
}

创建本地加载类  LocalLoader.java

public class LocalLoader extends AbstarctLoader {@Overrideprotected Bitmap onLoad(BitmapRequest request) {//得到本地图片的路径final String path = Uri.parse(request.getImageUrl()).getPath();File file = new File(path);if (!file.exists()) {return null;}BitmapDecoder decoder = new BitmapDecoder() {@Overrideprotected Bitmap decodeBitmapWithOption(BitmapFactory.Options options) {return BitmapFactory.decodeFile(path, options);}};return decoder.decoderBitmap(ImageviewHelper.getImageViewWidth(request.getImageView()),ImageviewHelper.getImageViewHeight(request.getImageView()));}
}

实现网络加载逻辑 UrlLoader.java

public class UrlLoader extends AbstarctLoader {@Overrideprotected Bitmap onLoad(final BitmapRequest request) {//先下载  后读取downloadImgByUrl(request.getImageUrl(), getCache(request.getImageUriMD5()));//解码图片BitmapDecoder bitmapDecoder = new BitmapDecoder() {@Overrideprotected Bitmap decodeBitmapWithOption(BitmapFactory.Options options) {//bitmap 对象值为空,因为读取的只是宽高return BitmapFactory.decodeFile(getCache(request.getImageUriMD5()).getAbsolutePath(), options);}};return bitmapDecoder.decoderBitmap(ImageviewHelper.getImageViewWidth(request.getImageView()),ImageviewHelper.getImageViewHeight(request.getImageView()));}public static boolean downloadImgByUrl(String urlStr, File file) {FileOutputStream fos = null;InputStream is = null;try {URL url = new URL(urlStr);HttpURLConnection conn = (HttpURLConnection) url.openConnection();is = conn.getInputStream();fos = new FileOutputStream(file);byte[] buf = new byte[512];int len = 0;while ((len = is.read(buf)) != -1) {fos.write(buf, 0, len);}fos.flush();return true;} catch (Exception e) {e.printStackTrace();} finally {try {if (is != null)is.close();} catch (IOException e) {}try {if (fos != null)fos.close();} catch (IOException e) {}}return false;}private File getCache(String unipue) {File file = new File(Environment.getExternalStorageDirectory(), "ImageLoader");if (!file.exists()) {file.mkdir();}return new File(file, unipue);}
当然如果你既不是本地的地址,也不是网络地址,就返回空的加载实现  NullLoader.java
public class NullLoader extends AbstarctLoader {@Overrideprotected Bitmap onLoad(BitmapRequest request) {return null;}
} 

创建一个加载管理类,把所有的加载类型管理,然后判断进行分发  LoaderManager.java

public class LoaderManager {//缓存所有支持的Loader类型private Map<String, Loader> mLoaderMap = new HashMap<>();private static LoaderManager mInstance = new LoaderManager();public static LoaderManager getInstance() {return mInstance;}private LoaderManager() {register("http", new UrlLoader());register("https", new UrlLoader());register("file", new LocalLoader());}private void register(String schema, Loader loader) {mLoaderMap.put(schema, loader);}public Loader getLoader(String schema) {if (mLoaderMap.containsKey(schema)) {return mLoaderMap.get(schema);}return new NullLoader();}
}

6、实现图片请求类  BitmapRequest.java

public class BitmapRequest implements Comparable<BitmapRequest> {public BitmapRequest(ImageView imageView, String imageUrl, Displayconfig displayconfig, SimpleImageLoader.ImageListener imageListener) {this.imageViewSoft = new SoftReference<>(imageView);//设置可见的image的Tag为要下载的图片路径imageView.setTag(imageUrl);this.imageUrl = imageUrl;this.imageListener = imageListener;if (displayconfig != null)this.displayconfig = displayconfig;this.imageUriMD5 = MD5Utils.toMD5(imageUrl);}public BitmapRequest(ImageView imageView, String imageUrl, SimpleImageLoader.ImageListener imageListener) {this.imageViewSoft = new SoftReference<>(imageView);//设置可见的image的Tag为要下载的图片路径imageView.setTag(imageUrl);this.imageUrl = imageUrl;this.imageListener = imageListener;this.imageUriMD5 = MD5Utils.toMD5(imageUrl);}private Displayconfig displayconfig;//持有ImageView的软应用private SoftReference<ImageView> imageViewSoft;//图片路径private String imageUrl;//MD5图片路径private String imageUriMD5;//下载完成监听public SimpleImageLoader.ImageListener imageListener;public String getImageUriMD5() {return imageUriMD5;}//加载策略private LoadPolicy loadPolicy = SimpleImageLoader.getInstance().getConfig().getLoadPolicy();//优先级编号private int serialNo;public int getSerialNo() {return serialNo;}public ImageView getImageView() {return imageViewSoft.get();}public String getImageUrl() {return this.imageUrl;}public void setSerialNo(int serialNo) {this.serialNo = serialNo;}public Displayconfig getDisplayConfig() {return displayconfig;}public LoadPolicy getLoadPolicy() {return loadPolicy;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;BitmapRequest that = (BitmapRequest) o;if (serialNo != that.serialNo) return false;return loadPolicy != null ? loadPolicy.equals(that.loadPolicy) : that.loadPolicy == null;}@Overridepublic int hashCode() {int result = loadPolicy != null ? loadPolicy.hashCode() : 0;result = 31 * result + serialNo;return result;}//确定优先级@Overridepublic int compareTo(BitmapRequest o) {return loadPolicy.compareto(o, this);}
}

实现请求队列   RequestQueue.java

public class RequestQueue {/*** 优先级阻塞式队列* 多线程共享* 生产效率和消费者效率差太远* 优先级高的队列先被消费* 每一个产品都有编号*/private BlockingQueue<BitmapRequest> mRequestsQueue = new PriorityBlockingQueue<>();/*** 转发器数量*/private int threadcount;//一组转发器private RequestDispatcher[] mDispatcher;private AtomicInteger i = new AtomicInteger(0);public RequestQueue(int threadcount) {this.threadcount = threadcount;}/*** 添加请求对象** @param request*/public void addRequest(BitmapRequest request) {//判断请求队列是否包含请求if (!mRequestsQueue.contains(request)) {//给请求进行编号request.setSerialNo(i.incrementAndGet());mRequestsQueue.add(request);} else {Log.w("", "请求已经存在  编号:" + request.getSerialNo());}}/*** 开启请求*/public void start() {//先停止,在开启stop();startDispatchers();}private void startDispatchers() {mDispatcher=new RequestDispatcher[threadcount];for (int i=0;i<threadcount;i++){RequestDispatcher dispatcher=new RequestDispatcher(mRequestsQueue);mDispatcher[i]=dispatcher;mDispatcher[i].start();}}/*** 停止请求*/public void stop() {}}

实现请求转发 RequestDispatcher.java

public class RequestDispatcher extends Thread { //转发器 --------请求转发线程,不断从请求队列获取请求//请求队列private BlockingQueue<BitmapRequest> mRequestQueue;public RequestDispatcher(BlockingQueue<BitmapRequest> mRequestQueue) {this.mRequestQueue = mRequestQueue;}@Overridepublic void run() {while (!isInterrupted()) {try {BitmapRequest request = mRequestQueue.take();/***  处理请求对象*/Log.i("wxf","imageurl:------->"+request.getImageUrl());String schema = pareSchema(request.getImageUrl());//获取加载器Loader loader = LoaderManager.getInstance().getLoader(schema);Log.i("wxf","loader------->"+loader);loader.loadImage(request);} catch (InterruptedException e) {e.printStackTrace();}}}private String pareSchema(String imageUrl) {if (imageUrl.contains("://")) {return imageUrl.split("://")[0];} else {Log.i("wxf", "不支持此类型");}return null;}
}

7、实现图片压缩类  BitmapDecoder.java

public abstract class BitmapDecoder {/*** 压缩图片* @param reqWidth* @param reqheight* @return 得到压缩后的图片*/public Bitmap decoderBitmap(int reqWidth, int reqheight) {//初始化OptionsBitmapFactory.Options options = new BitmapFactory.Options();//得到宽高信息,设置为true不会读取整张图片到内存options.inJustDecodeBounds = true;decodeBitmapWithOption(options);//计算图片缩放比例caculateSapleSizeOptions(options, reqWidth, reqheight);return decodeBitmapWithOption(options);}/*** 计算缩放比* @param options* @param reqWidth* @param reqHeight*/private void caculateSapleSizeOptions(BitmapFactory.Options options, int reqWidth, int reqHeight) {//计算缩放的比例//图片的原始宽高int width = options.outWidth;int height = options.outHeight;int inSampleSize = 1;//  reqWidth   ImageView的  宽if (width > reqWidth || height > reqHeight) {//宽高的缩放比例int heightRatio = Math.round((float) height / (float) reqHeight);int widthRatio = Math.round((float) width / (float) reqWidth);//有的图是长图、有的是宽图inSampleSize = Math.max(heightRatio, widthRatio);}//全景图//当inSampleSize为2,图片的宽与高变成原来的1/2//options.inSampleSize = 2options.inSampleSize = inSampleSize;//每个像素2个字节options.inPreferredConfig = Bitmap.Config.RGB_565;//Bitmap占用内存  trueoptions.inJustDecodeBounds = false;//当系统内存不足时可以回收Bitmapoptions.inPurgeable = true;options.inInputShareable = true;}protected abstract Bitmap decodeBitmapWithOption(BitmapFactory.Options options);
}

实现ImageView控件宽高获取   ImageviewHelper.java

public class ImageviewHelper {private static int DEFAULT_WIDTH = 200;private static int DEFAULT_HEIGHT = 200;public static int getImageViewWidth(ImageView imageView) {if (imageView != null) {ViewGroup.LayoutParams params = imageView.getLayoutParams();int width = 0;if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {width = imageView.getWidth();}if (width <= 0 && params != null) {width = params.width;}if (width <= 0) {width = getImageViewFieldValue(imageView, "mMaxWidth");}return width;}return DEFAULT_WIDTH;}public static int getImageViewHeight(ImageView imageView) {if (imageView != null) {ViewGroup.LayoutParams params = imageView.getLayoutParams();int height = 0;if (params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {height = imageView.getHeight();}if (height <= 0 && params != null) {height = params.height;}if (height <= 0) {height = getImageViewFieldValue(imageView, "mMaxHeight");}return height;}return DEFAULT_HEIGHT;}private static int getImageViewFieldValue(ImageView imageView, String fieldName) {try {Field field = ImageView.class.getDeclaredField(fieldName);field.setAccessible(true);int fieldValue = (int) field.get(imageView);if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {return fieldValue;}} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return 0;}}

MD5Utils帮助类

public class MD5Utils {private static MessageDigest digest;static {try {digest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {e.printStackTrace();Log.d("wxf", "md5 算法不支持!");}}/*** MD5加密** @param key* @return*/public static String toMD5(String key) {if (digest == null) {return String.valueOf(key.hashCode());}//更新字节digest.update(key.getBytes());//获取最终的摘要  十进制的  12345678/ABCD1245return convert2HexString(digest.digest());}/*** 转为16进制字符串** @param bytes* @return*/private static String convert2HexString(byte[] bytes) {StringBuffer sb = new StringBuffer();for (byte b : bytes) {//->8->08String hex = Integer.toHexString(0xFF & b);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}}

8、调用

public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter myAdapter;private List<Entity> mList = new ArrayList<>();SimpleImageLoader simpleImageLoader;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ImageLoaderConfig config = new ImageLoaderConfig.Builder().setThreadCount(3).setLoadpolicy(new ReversePolicy()).setCachePlicy(new DoubleCache(this)).setLoadingImage(R.mipmap.ic_launcher).setFailImage(R.mipmap.ic_launcher).build();simpleImageLoader = SimpleImageLoader.getInstance(config);for (int i = 0; i < 10; i++) {Entity entity = new Entity();entity.name = i + "fsfdsdfsafdsfsdf";mList.add(entity);}myAdapter = new MyAdapter(mList);recyclerView = (RecyclerView) findViewById(R.id.recyclerView);recyclerView.setLayoutManager(new GridLayoutManager(this, 2));recyclerView.setAdapter(myAdapter);}private class Entity {public String url;public String name;}private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {private List<Entity> tempList;public MyAdapter(List<Entity> mList) {this.tempList = mList;}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_newandrecommendlesson, parent, false);return new myViewHolder(view);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {((myViewHolder) holder).textView.setText("" + tempList.get(position).name);simpleImageLoader.displayImage(((myViewHolder) holder).imageView, Images[position]);}@Overridepublic int getItemCount() {return tempList.size();}}private class myViewHolder extends RecyclerView.ViewHolder {public TextView textView;public ImageView imageView;public myViewHolder(View itemView) {super(itemView);textView = (TextView) itemView.findViewById(R.id.item_newAndRecommendLesson_textView_title);imageView = (ImageView) itemView.findViewById(R.id.item_newAndRecommendLesson_imageView_pic);}}private String[] Images = {"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531129921916&di=13350c1a58f32683cfc90185f776d76f&imgtype=0&src=http%3A%2F%2Fpic-cdn.35pic.com%2F58pic%2F13%2F19%2F82%2F95g58PICtAm_1024.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130014832&di=57eec36f70f423eb3818e9cb8f4983c8&imgtype=0&src=http%3A%2F%2Ffa.topitme.com%2Fa%2F15%2F92%2F11216657698a59215ao.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130111946&di=55862e85879063bb85b76581b2b1b9dd&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F15%2F40%2F27%2F49B58PICXHQ_1024.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130126651&di=c28d13fab05f624522ab151241d6cb7d&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F12%2F29%2F66%2F40G58PIC9bI.jpg","https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1220481886,24258781&fm=27&gp=0.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130151235&di=31bfcab8733a3cba6b8f3e31efc17b09&imgtype=0&src=http%3A%2F%2Fdepot.nipic.com%2Ffile%2F20160628%2F21447645_11093515769.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130198048&di=f9b8f99097970275df3905ea6e919f3b&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F13%2F14%2F93%2F70w58PIChtV_1024.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130289265&di=e4cfbb4d53acfd1340180168bf67e23e&imgtype=0&src=http%3A%2F%2Fimg15.3lian.com%2F2015%2Ff2%2F159%2Fd%2F95.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130307728&di=1e1daaa961b9723c11d961ff8b017f33&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F86d6277f9e2f07083cebe627e224b899a901f22f.jpg","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531130316514&di=060abcc3e117b44d3432bed4634c0b81&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2Fcefc1e178a82b901ceb88214788da9773912ef84.jpg"};
}

注意:1、图片地址用MD5编码之后可是预防非法字符

2、别忘了添加读取和网络权限

    <uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3、DiskLruCache加载类的实现网上代码很多都是通用的,也可以在我的资源中下载

4、这个还没有实现图片的取消等,那个应该考虑Activity和Fragment然后根据生命周期去做相应的取消

Android 高仿ImageLoader图片加载相关推荐

  1. android 今日头条加载动画,高仿今日头条加载动画

    01 每每浏览手机app时,发现有的效果体验不错,作为一位程序员,总想要是自己来做,怎么实现. 今天我们来模仿今日头条的加载动画. 首先我们来看一下我们这个demo最终效果,有图有真相. 高仿今日头条 ...

  2. android qq底部图片选择器,Android 高仿QQ图片选择器

    当做一款APP,需要选择本地图片时,首先考虑的无疑是系统相册,但是Android手机五花八门,再者手机像素的提升,大图无法返回等异常因数,导致适配机型比较困难,微信.QQ都相继的在自己的APP里集成了 ...

  3. android菊花动画,Android实现仿iOS菊花加载圈动画效果

    常见的实现方式 切图,做旋转动画 自定义View,绘制效果 gif图 1.切图会增加体积,但相对简单,不过在换肤的场景下,会使用不同颜色,需要准备多张图,不够灵活. 2.由于自定义的好处,不同颜色只需 ...

  4. 仿新浪微博图片加载进度条——JLPieProgressView

    2019独角兽企业重金招聘Python工程师标准>>> JLPieProgressView 仿新浪微博图片加载进度条 实现代码如下: #import "JLPieProgr ...

  5. Android自助餐之大图片加载

    Android自助餐之大图片加载 原理 使用BitmapFactory.decodeStreeam()方法,该方法会调用native层代码来创建bitmap(两个重载都会调用) 使用带BitmapFa ...

  6. 圆形进度条(包括仿QQ图片加载进度图)

    原文:圆形进度条(包括仿QQ图片加载进度图) 源代码下载地址:http://www.zuidaima.com/share/1581277496822784.htm 以前找到的自定义圆形进度条

  7. Carson带你学Android:主流开源图片加载库对比(UIL、Picasso、Glide、Fresco)

    前言 图片加载在 Android开发项目中十分常见 为了降低开发周期 & 难度,我们经常会选用一些图片加载的开源库,而现在图片加载开源库越来越多,我们应该选用哪种呢? 今天.我就给大家介绍 & ...

  8. android 仿 动画,Android动画 - 仿58同城加载动画

    Android动画 - 仿58同城加载动画 效果图 58LoadingView.gif 分析动画 首先分析动画,如上图所示: 动画分为三部分,分别为上方跳动部分,中间阴影部分,和下方文字部分. 上方跳 ...

  9. Android自定义简单的图片加载器(ImageLoader)

    废话不多述,首先来说明下 为什么要用图片加载器 呢,就是为了避免图片重复从网络加载.也就是在第一次从网络加载之后就把图片缓存在本地,下次用的时候直接从本地查找,有的话就直接用,没有再从网络加载. 加载 ...

最新文章

  1. python计算条件概率_用Python实现贝叶斯定理(附代码)
  2. Java 11:新的HTTP客户端API
  3. 商品订单打印模板html,【EXCEL】如何制作订单单据查询与打印模板?
  4. 如何打开别人的Android项目
  5. 复盘2020:那些崛起的公司
  6. 深入SpringBoot源码(二)getSpringFactoriesInstances方法详解
  7. extern关键字的作用
  8. poj 1436 Horizontally Visible Segments(线段树)
  9. 计算机开始栏没有启动项,win7系统快速启动栏里面的快速启动项没有了并且无法添加,怎么处理?...
  10. 添加Win10文件夹详细信息------统一显示内容
  11. Python3.X网络爬虫学习(六)
  12. 微信小程序开发之——数据存储Storage
  13. Hadoop学习(一)
  14. 计算机文件打开方式这么还原,dat文件还原默认打开方式如何设置?还原默认打开方式的详细步骤...
  15. oracle电子商务套件使用手册,甲骨文电子商务套件操作.pdf
  16. 应聘web前端开发面试时问到的基础问题
  17. 踏浪前行 ——读《浪潮之巅》
  18. 基于QT的指挥猫猫打架玩耍的小游戏设计
  19. 机器学习笔记 - 什么是条件随机场?
  20. python向数据库插入字符串数据,字符串中含有单引号,入库报错解决办法

热门文章

  1. mysql触发器 生僻字_mysql 生僻字亂碼
  2. org.apache.ibatis.executor.ExecutorException: No constructor xx matching [java.lang.Long, java.lang]
  3. in on_json_loading_failed ==> raise BadRequest() ==> werkzeug.exceptions.BadRequest: 400 Bad Request
  4. python爬取图片实例_Python简单爬取图片实例
  5. SMAP数据产品下载方法与处理方法
  6. HDU 4499 DFS
  7. 关于十六进制颜色编码
  8. Python进阶篇:百度指数解密【抓包|JS逆向|数据区分】
  9. Apollo阿波罗配置中心
  10. iPhone应用程序适配iPad mini