ImageLoader

xiaoxiao2021-02-28  56

public class ImageLoader { public static final int UNCONSTRAINED = -1; private static final String TAG = "ImageLoader"; private static final boolean DEBUG = false; // Queue of work to do in the worker thread. The work is done in order. private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>(); // the worker thread and a done flag so we know when to exit private boolean mDone; private Thread mDecodeThread; private ContentResolver mCr; private LruCache<String, Bitmap> memoryCache; private static Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { Map<String, Object> data = (Map<String, Object>) msg.obj; WorkItem workItem = (WorkItem) data.get("workItem"); Bitmap bitmap = (Bitmap) data.get("bitmap"); workItem.mOnLoadedRunnable.onLoadingComplete(bitmap); if (DEBUG) Log.i(TAG, String.valueOf(workItem.mImage.getId()) + workItem.mIsThumb + " called listener"); return false; } }); public void getBitmap(ImageData image, OnLoaderCompleteListener imageLoadedRunnable, boolean isThumb) { if (mDecodeThread == null) { start(); } synchronized (mQueue) { WorkItem w = new WorkItem(image, imageLoadedRunnable, isThumb); mQueue.add(w); mQueue.notifyAll(); } } /** * @param filePath 文件路径 * @return 文件数据 */ public Bitmap getBitmapFromPath(int minSideLength, int maxNumOfPixels, String filePath) { try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, minSideLength, maxNumOfPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; return BitmapFactory.decodeFile(filePath, options); } catch (OutOfMemoryError ex) { Log.e(TAG, "Got oom exception ", ex); return null; } } public Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, BitmapFactory.Options options) { try { if (pfd == null) pfd = makeInputStream(uri, cr); if (pfd == null) return null; if (options == null) options = new BitmapFactory.Options(); FileDescriptor fd = pfd.getFileDescriptor(); options.inJustDecodeBounds = true; // BitmapManager.instance().decodeFileDescriptor(fd, options); BitmapFactory.decodeFileDescriptor(fd, null, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, minSideLength, maxNumOfPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; return BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (OutOfMemoryError ex) { Log.e(TAG, "Got oom exception ", ex); return null; } finally { closeSilently(pfd); } } public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == UNCONSTRAINED) && (minSideLength == UNCONSTRAINED)) { return 1; } else if (minSideLength == UNCONSTRAINED) { return lowerBound; } else { return upperBound; } } private ParcelFileDescriptor makeInputStream( Uri uri, ContentResolver cr) { try { return cr.openFileDescriptor(uri, "r"); } catch (IOException ex) { return null; } } public void closeSilently(ParcelFileDescriptor c) { if (c == null) return; try { c.close(); } catch (Throwable t) { // do nothing } } public boolean cancel(final ImageData image) { synchronized (mQueue) { int index = findItem(image); if (index >= 0) { mQueue.remove(index); return true; } else { return false; } } } // The caller should hold mQueue lock. private int findItem(ImageData image) { for (int i = 0; i < mQueue.size(); i++) { if (mQueue.get(i).mImage == image) { return i; } } return -1; } // Clear the queue. Returns an array of tags that were in the queue. public void clearQueue() { synchronized (mQueue) { for (WorkItem workItem : mQueue) { workItem.mImage = null; workItem.mOnLoadedRunnable = null; } mQueue.clear(); } } private static class WorkItem { ImageData mImage; OnLoaderCompleteListener mOnLoadedRunnable; boolean mIsThumb; WorkItem(ImageData image, OnLoaderCompleteListener onLoadedRunnable, boolean isThumb) { mImage = image; mOnLoadedRunnable = onLoadedRunnable; mIsThumb = isThumb; } } public ImageLoader(ContentResolver cr) { mCr = cr; //获取系统分配给每个应用程序的最大内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int mCacheSize = maxMemory / 2; //给LruCache分配1/2最大内存 memoryCache = new LruCache<String, Bitmap>(mCacheSize) { //必须重写此方法,来测量Bitmap的大小 @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } /** * 当bitmap被清出缓存的时候,回收所占内存 */ @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { if (key.contains("false")) { oldValue.recycle(); oldValue = null; } if (DEBUG) Log.i(TAG, key + " is removed from cache"); } }; start(); } private void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null && bitmap != null) { memoryCache.put(key, bitmap); } } private Bitmap getBitmapFromMemCache(String key) { return memoryCache.get(key); } private class WorkerThread implements Runnable { // Pick off items on the queue, one by one, and compute their bitmap. // Place the resulting bitmap in the cache, then call back by executing // the given runnable so things can get updated appropriately. public void run() { while (true) { WorkItem workItem = null; synchronized (mQueue) { if (mDone) { break; } if (!mQueue.isEmpty()) { workItem = mQueue.remove(0); } else { try { mQueue.wait(); } catch (InterruptedException ex) { // ignore the exception } continue; } } Message msg = new Message(); Map<String, Object> msgMap = new HashMap<>(); msgMap.put("workItem", workItem); Bitmap bitmap = getBitmapFromMemCache(String.valueOf(workItem.mImage.getId()) + workItem.mIsThumb); if (bitmap == null) { if (workItem.mImage.getType() == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) { if (workItem.mIsThumb) { long longId = workItem.mImage.getId(); BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmap = MediaStore.Video.Thumbnails.getThumbnail(mCr, longId, MediaStore.Images.Thumbnails.MINI_KIND, bitmapOptions); } else { try { MediaMetadataRetriever media = new MediaMetadataRetriever(); media.setDataSource(workItem.mImage.getPath()); bitmap = media.getFrameAtTime(); } catch (Exception e) { Log.e(TAG, "get video bitmap error."); e.printStackTrace(); bitmap = null; } } } else if (workItem.mImage.getType() == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) { if (workItem.mIsThumb) { long longId = workItem.mImage.getId(); BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmap = MediaStore.Images.Thumbnails.getThumbnail(mCr, longId, MediaStore.Images.Thumbnails.MINI_KIND, bitmapOptions); } else { bitmap = makeBitmap(UNCONSTRAINED, 3 * 1024 * 1024, workItem.mImage.getUri(), mCr, null, null); } } if (bitmap != null) { addBitmapToMemoryCache(String.valueOf(workItem.mImage.getId()) + workItem.mIsThumb, bitmap); if (DEBUG) Log.i(TAG, String.valueOf(workItem.mImage.getId()) + workItem.mIsThumb + " is put in cache"); } } msgMap.put("bitmap", bitmap); msg.obj = msgMap; handler.sendMessage(msg); } } } private void start() { if (mDecodeThread != null) { return; } mDone = false; Thread t = new Thread(new WorkerThread()); t.setName("image-loader"); mDecodeThread = t; t.start(); } public void stop() { synchronized (mQueue) { mDone = true; mQueue.notifyAll(); } if (mDecodeThread != null) { try { Thread t = mDecodeThread; MediaStore.Images.Thumbnails.cancelThumbnailRequest(mCr, -1, t.getId()); MediaStore.Video.Thumbnails.cancelThumbnailRequest(mCr, -1, t.getId()); t.join(); mDecodeThread = null; } catch (InterruptedException ex) { // so now what? } } } public interface OnLoaderCompleteListener { void onLoadingComplete(Bitmap bitmap); } }
转载请注明原文地址: https://www.6miu.com/read-75496.html

最新回复(0)