美文网首页
ImageLoader工具类

ImageLoader工具类

作者: 古早味蛋糕 | 来源:发表于2019-08-03 17:47 被阅读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;
        }
      }
    }
    

    相关文章

      网友评论

          本文标题:ImageLoader工具类

          本文链接:https://www.haomeiwen.com/subject/cyxsdctx.html