ImageLoader工具类

2019-08-03  本文已影响0人  古早味蛋糕

功能详解点击 :https://www.jianshu.com/p/0cd4b6bd516e

public class ImageLoader {
private static final String TAG="ImageLoader:";
public static final int MESSAGE_POST_RESULT=1;
private static final int CPU_COUNT=Runtime.getRuntime().availableProcessors();//得到cpu的个数
private static final int CORE_POOL_SIZE=CPU_COUNT+1;
private static final int MAXIMUM_POOL_SIZE= CPU_COUNT*2+1;//2倍的cpu个数加1
private static final long KEEP_ALIVE=10L;
private static final int TAG_KEY_URI=R.id.image_demo6;//R.id.image_uri
private static final long DISK_CACHCE_SIZE=1024*1024*8;
private static final int IO_BUFFER_SIZE=1024*8;
private static final int DISK_CACHCE_INFEX=0;
private boolean mIsDiskLruCacheCreated=false;

//创建线程工厂
private static  final ThreadFactory sThreadFactory =new ThreadFactory() {
    private final AtomicInteger mCount=new AtomicInteger(1);
    @Override
    public Thread newThread(@NonNull Runnable r) {
        return new Thread(r,"ImageLoader:"+mCount.getAndIncrement());
    }
};
//线程池创建
public static final Executor THERAD_POOL_EXECUTOR=new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,
        KEEP_ALIVE, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(),sThreadFactory);
//通过handler 在设置图片之前都会检查它的url有没有改变,如果发生改变就不再给它设置图片。这样可以解决图片错位问题
private Handler mMainHandler=new Handler(Looper.getMainLooper()){
    @Override
    public void handleMessage(Message msg) {
        LoaderResult result= (LoaderResult) msg.obj;
        ImageView imageView=result.imageView;
        imageView.setImageBitmap(result.bitmap);
        String uri= (String) imageView.getTag(TAG_KEY_URI);
        if (uri.equals(result.uri)){
            imageView.setImageBitmap(result.bitmap);
        }else {
            Log.w(TAG,"set image bitmap,but url has changed , ignored!");
        }
    }
};

private Context mContext;
private ImageResizer mImageResizer=new ImageResizer();
private LruCache<String,Bitmap> mMemoryCache;
private DiskLruCache mDiskLruCache;
private ImageLoader(Context context){
    mContext=context.getApplicationContext();
    //maxMemory是拿到的程序最大可以使用的内存以k为单位
    int maxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
    int cacheSize=maxMemory/8;
    mMemoryCache=new LruCache<String, Bitmap>(cacheSize){
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getRowBytes()*bitmap.getHeight()/1024;
        }
    };
    File diskCacheDir =getDiskCacheDir(mContext,"bitmap");
    if (!diskCacheDir.exists()){
        diskCacheDir.mkdirs();
    }
    if (getUsableSpace(diskCacheDir)>DISK_CACHCE_SIZE){
        try {
            mDiskLruCache=DiskLruCache.open(diskCacheDir,1,1,DISK_CACHCE_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mIsDiskLruCacheCreated=true;
    }

}

public static ImageLoader build(Context context){
    return new ImageLoader(context);
}
//添加缓存数据
private void addBitmapToMemoryCache(String key,Bitmap bitmap){
    if (getBitmapFromMemCache(key)==null){
        mMemoryCache.put(key,bitmap);
    }
}
//添加读取数据
private Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}

public void bindBitmap(final String uri, final ImageView imageView){
    bindBitmap(uri,imageView,0,0);
}
//异步加载
public void bindBitmap(final String uri, final ImageView imageView, final int reqWidth,final int reqHeight){
    imageView.setTag(TAG_KEY_URI,uri);
    final Bitmap bitmap=loadBitmapFromMemCache(uri);
    if (bitmap!=null){
        imageView.setImageBitmap(bitmap);
        return;
    }
    final Runnable loadBitmapTask=new Runnable() {
        @Override
        public void run() {
            Bitmap bitmapp=loadBitmap(uri,reqWidth,reqHeight);
            if (bitmap!=null){
                LoaderResult result=new LoaderResult(imageView,uri,bitmap);
                mMainHandler.obtainMessage(MESSAGE_POST_RESULT,result).sendToTarget();
            }
        }
    };
    THERAD_POOL_EXECUTOR.execute(loadBitmapTask);
}

//同步加载
private Bitmap loadBitmap(String uri, int reqWidth, int reqHeight) {
    Bitmap bitmap=loadBitmapFromMemCache(uri);
    if (bitmap!=null){
        Log.d(TAG, "loadBitmapFromMemCache: uri = "+uri);
        return bitmap;
    }
    try {
        bitmap=loadBitmapFromMemDiskCache(uri,reqWidth,reqHeight);
        if (bitmap!=null){
            Log.d(TAG, "loadBitmapFromMemDiskCache: uri = "+uri);
            return bitmap;
        }
        bitmap=loadBitmapFromHttp(uri,reqWidth,reqHeight);
        if (bitmap!=null){
            Log.d(TAG, "loadBitmapFromHttp: uri = "+uri);
            return bitmap;
        }
    }catch (Exception e){
        e.printStackTrace();
    }

    if (bitmap==null&&!mIsDiskLruCacheCreated){
        Log.w(TAG, "encounter error ,DiskLruCache is not created .");
        bitmap=downloadBitmapFromUrl(uri);
    }

    return bitmap;
}




private Bitmap loadBitmapFromMemCache(String uri) {
    final String key=hashKeyFormUrl(uri);
    Bitmap bitmap=getBitmapFromMemCache(key);
    return bitmap;
}

//磁盘缓存读取
private Bitmap loadBitmapFromMemDiskCache(String uri, int reqWidth, int reqHeight) throws IOException{
    if (Looper.myLooper()==Looper.getMainLooper()){
        throw new RuntimeException("can not visit network from UI Thread .");
    }
    if (mDiskLruCache==null){
        return null;
    }
    Bitmap bitmap=null;
    String key=hashKeyFormUrl(uri);
    DiskLruCache.Snapshot snapshot=mDiskLruCache.get(key);
    if (snapshot!=null){
        FileInputStream fileInputStream=(FileInputStream)snapshot.getInputStream(DISK_CACHCE_INFEX);
        FileDescriptor fileDescriptor=fileInputStream.getFD();
        bitmap=mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDescriptor,reqWidth,reqHeight);
        if (bitmap!=null){
            addBitmapToMemoryCache(key,bitmap);
        }
    }
    return bitmap;
}


private Bitmap loadBitmapFromHttp(String uri, int reqWidth, int reqHeight) throws IOException{
    //判断当前线程是不是主线程
    if (Looper.myLooper()==Looper.getMainLooper()){
        throw new RuntimeException("can not visit network from UI Thread .");
    }
    if (mDiskLruCache==null){
        return null;
    }
    String key=hashKeyFormUrl(uri);
    //通过 Editor 可以得到一个文件输出流
    DiskLruCache.Editor editor =mDiskLruCache.edit(key);
    if (editor !=null){
        //由于DiskLruCache的 open 方法在前面设置了一个节点只能有一个数据,所以 DISK_CACHCE_INFEX 设为0就可
        OutputStream outputStream=editor.newOutputStream(DISK_CACHCE_INFEX);
        if (downloadUrlToStream(uri,outputStream)){
            editor.commit();
        }else {
            editor.abort();
        }
        mDiskLruCache.flush();
    }
    return loadBitmapFromMemDiskCache(uri,reqWidth,reqHeight);
}
//通过文件输出流写入到文件系统上
private boolean downloadUrlToStream(String uriString, OutputStream outputStream) {
    HttpURLConnection urlConnection=null;
    BufferedOutputStream out=null;
    BufferedInputStream in=null;
    try {
        final URL url =new URL(uriString);
        urlConnection= (HttpURLConnection) url.openConnection();
        in=new BufferedInputStream(urlConnection.getInputStream(),IO_BUFFER_SIZE);
        out=new BufferedOutputStream(outputStream,IO_BUFFER_SIZE);

        int b;
        while ((b=in.read())!=-1){
            out.write(b);
        }
        return true;
    } catch (IOException e) {
        Log.e(TAG, "downLoadBitmap failed ,"+e );
    }finally {
        if (urlConnection!=null){
            urlConnection.disconnect();
        }
        try {
            out.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return false;
}

private Bitmap downloadBitmapFromUrl(String uri) {
    Bitmap bitmap=null;
    HttpURLConnection urlConnection=null;
    BufferedInputStream in=null;

    try {
        final URL url = new URL(uri);
        urlConnection= (HttpURLConnection) url.openConnection();
        in=new BufferedInputStream(urlConnection.getInputStream(),IO_BUFFER_SIZE);
        bitmap= BitmapFactory.decodeStream(in);
    } catch (IOException e) {
        Log.e(TAG, "downLoadBitmap failed ,"+e );
    }finally {
        if (urlConnection!=null){
            urlConnection.disconnect();
        }
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return bitmap;
}
//磁盘缓存添加
private String hashKeyFormUrl(String uri) {
    String cacheKey = null;
    try {
        //图片的url中很可能有特殊字符,这将影响url在android中的使用,所以一般采用url的md5值作为key
        final MessageDigest mDigest=MessageDigest.getInstance("MD5");
        mDigest.update(uri.getBytes());
        cacheKey=bytesToHexString(mDigest.digest());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return cacheKey;
}

private String bytesToHexString(byte[] bytes) {
    StringBuilder sb=new StringBuilder();
    for (int i = 0; i < bytes.length; i++) {
        //此方法返回的字符串表示的无符号整数参数所表示的值以十六进制(基数为16)
        String hex=Integer.toHexString(0xFF & bytes[i]);
        if (hex.length()==1){
            sb.append('0');
        }
        sb.append(hex);
    }
    return sb.toString();
}

private File getDiskCacheDir(Context mContext, String uniqueName) {
    boolean externalStorageAvailable= Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    final String cachePath;
    if (externalStorageAvailable){
        cachePath=mContext.getExternalCacheDir().getPath();
    }else {
        cachePath=mContext.getCacheDir().getPath();
    }
    return new File(cachePath+File.separator+uniqueName);
}

//StatFs类 获取系统/sdcard存储空间信息
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private long getUsableSpace(File path){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD){
        return path.getUsableSpace();
    }
    final StatFs statFs =new StatFs(path.getPath());
    return statFs.getBlockSizeLong()*statFs.getAvailableBlocksLong();

}

private static class LoaderResult{
    public ImageView imageView;
    public String uri;
    public Bitmap bitmap;

    public LoaderResult(ImageView imageView, String uri, Bitmap bitmap) {
        this.imageView = imageView;
        this.uri = uri;
        this.bitmap = bitmap;
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读