/* * Copyright 2015 Yan Zhenjie * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yanzhenjie.nohttp.tools; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; import com.yanzhenjie.nohttp.Logger; import com.yanzhenjie.nohttp.HandlerDelivery; import com.yanzhenjie.nohttp.NoHttp; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created in Nov 4, 2015 3:07:29 PM. * * @author Yan Zhenjie. */ public class ImageLocalLoader { /** * Single module. */ private static ImageLocalLoader mInstance; /** * Default gray image. */ private Drawable mDefaultDrawable; /** * Image cache. */ private LruCache<String, Bitmap> mLruCache; /** * Thread pool. */ private ExecutorService mExecutorService; /** * Get single object. * * @return {@link ImageLocalLoader}. */ public static ImageLocalLoader getInstance() { synchronized (ImageLocalLoader.class) { if (mInstance == null) { mInstance = new ImageLocalLoader(); } } return mInstance; } private ImageLocalLoader() { mDefaultDrawable = new ColorDrawable(Color.GRAY); mExecutorService = Executors.newSingleThreadExecutor(); int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 8); mLruCache = new LruCache<String, Bitmap>(maxMemory) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; } /** * Deposit in the province read images, width is high, the greater the picture clearer, but also the memory. * * @param imagePath pictures in the path of the memory card. * @param maxWidth the highest limit value target width. * @param maxHeight the highest limit value target height. * @return Bitmap */ public Bitmap readImage(String imagePath, int maxWidth, int maxHeight) { File imageFile = new File(imagePath); if (imageFile.exists()) { InputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(imageFile)); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(inputStream, null, options); inputStream.close(); int i = 0; while (true) { if ((options.outWidth >> i <= maxWidth) && (options.outHeight >> i <= maxHeight)) { inputStream = new BufferedInputStream(new FileInputStream(new File(imagePath))); options.inSampleSize = (int) Math.pow(2.0, i); options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options); inputStream.close(); return bitmap; } i += 1; } } catch (IOException e) { Logger.e(e, "This path does not exist" + imagePath + "."); } finally { IOUtils.closeQuietly(inputStream); } } return null; } /** * According to the ImageView obtains appropriate width and height of compression. * * @param imageView {@link ImageView}. * @param viewSizes ViewSize. */ public void measureSize(ImageView imageView, int[] viewSizes) { final DisplayMetrics displayMetrics = NoHttp.getContext().getResources().getDisplayMetrics(); final LayoutParams params = imageView.getLayoutParams(); if (params == null) { viewSizes[0] = displayMetrics.widthPixels; viewSizes[1] = displayMetrics.heightPixels; } else { viewSizes[0] = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView.getWidth(); // Get actual image // width viewSizes[1] = params.height == LayoutParams.WRAP_CONTENT ? 0 : imageView.getHeight(); // Get actual // image height if (viewSizes[0] <= 0) viewSizes[0] = displayMetrics.widthPixels; // Get layout width parameter if (viewSizes[1] <= 0) viewSizes[1] = displayMetrics.heightPixels; // Get layout height parameter } } /** * Set the default image, resId from drawable. Is displayed when loading or loading failure. * * @param resId res id. */ @SuppressLint("NewApi") public void setDefaultImage(int resId) { mDefaultDrawable = ResCompat.getDrawable(resId); } /** * Set the default image, resId from drawable. Is displayed when loading or loading failure. * * @param color color. */ public void setDefaultImageColor(int color) { mDefaultDrawable = new ColorDrawable(color); } /** * Load image from local SDCard. * * @param imageView {@link ImageView}. * @param imagePath path. */ public void loadImage(ImageView imageView, String imagePath) { loadImage(imageView, imagePath, 0, 0, null); } /** * Load image from local SDCard. * * @param imageView {@link ImageView}. * @param imagePath path. * @param imageLoadListener {@link ImageLoadListener}. */ public void loadImage(ImageView imageView, String imagePath, ImageLoadListener imageLoadListener) { loadImage(imageView, imagePath, 0, 0, imageLoadListener); } /** * Load image from local SDCard. * * @param imageView {@link ImageView}. * @param imagePath path. * @param width width. * @param height height. */ public void loadImage(ImageView imageView, String imagePath, int width, int height) { loadImage(imageView, imagePath, width, height, null); } /** * According to the specified width high loading pictures, wide high, the greater the picture clearer, more memory. * * @param imageView {@link ImageView}. * @param imagePath path from local SDCard. * @param width target width. * @param height target height. * @param imageLoadListener {@link ImageLoadListener}. */ public void loadImage(ImageView imageView, String imagePath, int width, int height, ImageLoadListener imageLoadListener) { if (imageLoadListener == null) imageView.setTag(imagePath); Bitmap bitmap = getImageFromCache(imagePath + width + height); if (bitmap == null) { imageView.setImageDrawable(mDefaultDrawable); mExecutorService.execute(new TaskThread(imageView, imagePath, width, height, imageLoadListener)); } else { ImgBeanHolder holder = new ImgBeanHolder(); holder.imageView = imageView; holder.imagePath = imagePath; holder.bitmap = bitmap; holder.imageLoadListener = imageLoadListener; HandlerDelivery.getInstance().post(holder); } } private Bitmap getImageFromCache(String key) { return mLruCache.get(key); } private void addImageToCache(String key, Bitmap bitmap) { if (getImageFromCache(key) == null && bitmap != null) mLruCache.put(key, bitmap); } private class TaskThread implements Runnable { private ImageView mImageView; private String mImagePath; private int width; private int height; private ImageLoadListener imageLoadListener; TaskThread(ImageView imageView, String imagePath, int width, int height, ImageLoadListener imageLoadListener) { this.mImagePath = imagePath; this.mImageView = imageView; this.width = width; this.height = height; this.imageLoadListener = imageLoadListener; } @Override public void run() { if (TextUtils.isEmpty(mImagePath)) Logger.e("The image path is null"); else { Bitmap bitmap; if (width != 0 && height != 0) bitmap = readImage(mImagePath, width, height); else { int[] viewSizes = new int[2]; measureSize(mImageView, viewSizes); bitmap = readImage(mImagePath, viewSizes[0], viewSizes[1]); } addImageToCache(mImagePath + width + height, bitmap); ImgBeanHolder holder = new ImgBeanHolder(); holder.bitmap = getImageFromCache(mImagePath + width + height); holder.imageView = mImageView; holder.imagePath = mImagePath; holder.imageLoadListener = imageLoadListener; HandlerDelivery.getInstance().post(holder); } } } private class ImgBeanHolder implements Runnable { Bitmap bitmap; ImageView imageView; String imagePath; ImageLoadListener imageLoadListener; @Override public void run() { if (imagePath.equals(imageView.getTag())) { if (bitmap == null) imageView.setImageDrawable(mDefaultDrawable); else imageView.setImageBitmap(bitmap); } if (imageLoadListener != null) { if (bitmap != null) imageLoadListener.onLoadSucceed(imageView, bitmap, imagePath); else imageLoadListener.onLoadFailed(imageView, imagePath); } } } public interface ImageLoadListener { void onLoadSucceed(ImageView imageView, Bitmap bitmap, String imagePath); void onLoadFailed(ImageView imageView, String imagePath); } }