Android list加载图片工具类
总体思路
Handler + looper + message
核心类
- package com.base.imagechoose.util;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.support.v4.util.LruCache;
- import android.util.DisplayMetrics;
- import android.view.ViewGroup;
- import android.widget.ImageView;
- import java.lang.reflect.Field;
- import java.util.LinkedList;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- /**
- * 图片加载类
- */
- public class ImageLoader {
- private static ImageLoader mInstance;
- /**
- * 图片缓存
- */
- private LruCache<String, Bitmap> mLruCache;
- private ExecutorService mThreadPool;//线程池, 加载任务
- private static final int DAFULT_THREAD_COUNT = 1; //线程数量
- /**
- * 队列调度方式
- */
- private Type mType = Type.FIFO;
- /**
- * 任务队列
- */
- private LinkedList<Runnable> mTaskQueue;
- /**
- * 后台轮询线程
- */
- private Thread mPoolThread;
- private Handler mPoolTheadHandler;
- //信号量同步mPoolTheadHandler
- private Semaphore mSemaphorePoolTheadHandler = new Semaphore(0);
- /**
- * 用Semaphore来控制一个线程执行完才执行下一个
- */
- private Semaphore mSemaphorePool; //用信号量来达到线程Type规则
- /**
- * UI线程中的Handler
- */
- private Handler mUIHandler;
- //先进先出
- public enum Type {
- FIFO, FIFI;
- }
- private ImageLoader(int threadCount, Type type) {
- init(threadCount, type);
- }
- public static ImageLoader getInstance() {
- if (mInstance == null) {
- synchronized (ImageLoader.class) {
- if (mInstance == null) {
- mInstance = new ImageLoader(DAFULT_THREAD_COUNT, Type.FIFO);
- }
- }
- }
- return mInstance;
- }
- public static ImageLoader getInstance(int threadCount, Type type) {
- if (mInstance == null) {
- synchronized (ImageLoader.class) {
- if (mInstance == null) {
- mInstance = new ImageLoader(threadCount, type);
- }
- }
- }
- return mInstance;
- }
- private void init(int threadCount, Type type) {
- //后台轮询线程
- mPoolThread = new Thread(){
- @Override
- public void run() {
- Looper.prepare();
- mPoolTheadHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- //线程池去取出一个任务进行执行
- mThreadPool.execute(getTask());
- try {
- //如果信号量为3,到第4个就会阻塞住
- mSemaphorePool.acquire();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- //释放一个信号量
- mSemaphorePoolTheadHandler.release();
- Looper.loop();
- }
- };
- mPoolThread.start();
- //获取应用的最大可用内存
- int maxMemory = (int) Runtime.getRuntime().maxMemory();
- //设置缓存空间
- int cacheMemory = maxMemory/8;
- //初始化缓存
- mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- //返回内存,value每一行的大小*高度
- return value.getRowBytes()*value.getHeight();
- }
- };
- //创建线程池
- mThreadPool = Executors.newFixedThreadPool(threadCount);
- //初始化任务队列
- mTaskQueue = new LinkedList<>();
- mType = type;
- mSemaphorePool = new Semaphore(threadCount);
- }
- /**
- * 从任务队列取出一个方法
- * @return
- */
- private Runnable getTask() {
- if (mType == Type.FIFO) {
- return mTaskQueue.removeFirst();
- } else {
- return mTaskQueue.removeLast();
- }
- }
- /**
- * 根据path为控件加载图片
- * @param path 路径
- * @param imageView 控件
- */
- public void loadImage(final String path, final ImageView imageView) {
- imageView.setTag(path);
- if (mUIHandler == null) {
- mUIHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- //获取得到的图片并在控件上显示
- ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
- //当tag为传入path时才进行赋值
- if (holder.imageView.getTag().equals(holder.path)) {
- holder.imageView.setImageBitmap(holder.bm);
- }
- }
- };
- }
- //根据path在缓存中获取图片
- Bitmap bm = getBitmapFromLruCache(path);
- if (bm != null) {
- refreashBitmap(path, imageView, bm);
- } else {
- //没有图片,添加一个任务
- addTasks(new Runnable(){
- @Override
- public void run() {
- //加载图片
- //图片压缩
- //1.获得图片需要显示的大小
- ImageSize imageSize = getImageViewSize(imageView);
- //2.压缩图片
- Bitmap bm = decodeSampleBitmapFromPath(path, imageSize.width, imageSize.height);
- //3.把图片加入缓存
- addBitmapToLruCache(path,bm);
- refreashBitmap(path, imageView, bm);
- //当前任务执行完后释放信号量
- mSemaphorePool.release();
- }
- });
- }
- }
- /**
- * 发送handler显示图片
- * @param path
- * @param imageView
- * @param bm
- */
- private void refreashBitmap(String path, ImageView imageView, Bitmap bm) {
- Message message = new Message();
- ImgBeanHolder imgBeanHolder = new ImgBeanHolder();
- imgBeanHolder.bm = bm;
- imgBeanHolder.imageView = imageView;
- imgBeanHolder.path = path;
- message.obj = imgBeanHolder;
- mUIHandler.sendMessage(message);
- }
- /**
- * 将图片放入缓存
- * @param path
- * @param bm
- */
- private void addBitmapToLruCache(String path, Bitmap bm) {
- if(getBitmapFromLruCache(path) == null) {
- if (bm != null) {
- mLruCache.put(path, bm);
- }
- }
- }
- /**
- * 添加任务
- * @param runnable
- */
- private synchronized void addTasks(Runnable runnable) {
- //将任务放入任务队列中
- mTaskQueue.add(runnable);
- //发送一个通知去通知后台轮询执行任务
- try {
- if (mPoolTheadHandler == null)
- mSemaphorePoolTheadHandler.acquire();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- mPoolTheadHandler.sendEmptyMessage(0x110);
- }
- /**
- * 根据path在缓存中获取图片
- * @param key
- * @return
- */
- private Bitmap getBitmapFromLruCache(String key) {
- return mLruCache.get(key);
- }
- /**
- * 根据imageview获取图片需要压缩的宽和高
- * @param imageView
- */
- private ImageSize getImageViewSize(ImageView imageView) {
- ImageSize imageSize = new ImageSize();
- DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();
- ViewGroup.LayoutParams lp = imageView.getLayoutParams();
- int width = imageView.getWidth();
- if (width <= 0) {
- width = lp.width; //获取imageview在layout中声明的亮度
- }
- if (width <= 0) {
- width = getImageViewFileValue(imageView, "mMaxWidth"); //检查最大值
- }
- if (width <= 0) {
- width = displayMetrics.widthPixels;
- }
- int height = imageView.getHeight();
- if (height <= 0) {
- height = lp.height; //获取imageview在layout中声明的亮度
- }
- if (height <= 0) {
- height = getImageViewFileValue(imageView, "mMaxHeight"); //检查最大值 //检查最大值
- }
- if (height <= 0) {
- height = displayMetrics.heightPixels;
- }
- imageSize.width = width;
- imageSize.height = height;
- return imageSize;
- }
- private static int getImageViewFileValue(Object object,String fileName) {
- int value = 0;
- //得到当前ImageView的字段集合
- try {
- Field field = ImageView.class.getDeclaredField(fileName);
- field.setAccessible(true);
- int fieldValue = field.getInt(object);
- if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
- value = fieldValue;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return value;
- }
- /**
- * 根据图片需要的宽高对图片进行压缩
- * @param path
- * @param width
- * @param height
- * @return
- */
- private Bitmap decodeSampleBitmapFromPath(String path, int width, int height) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- //不加入内存
- options.inJustDecodeBounds = true;
- //获取实际的options
- BitmapFactory.decodeFile(path, options);
- //用实际的options和需要显示的宽高算出inSampleSize
- options.inSampleSize = caculateInSampleSize(options, width, height);
- //使用获取的inSampleSize再次解析图片
- //放入内存
- options.inJustDecodeBounds = false;
- Bitmap bitmap = BitmapFactory.decodeFile(path, options);
- return bitmap;
- }
- /**
- * 用实际的options和需要显示的宽高算出inSampleSize
- * @param options
- * @param reqWidth
- * @param reqHeight
- * @return
- */
- private int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
- int width = options.outWidth;
- int height = options.outHeight;
- int inSampleSize = 1;
- if (width > reqHeight || height > reqHeight) {
- int widthRadio = Math.round(width*1.0f/reqWidth);
- int heightRadio = Math.round(height*1.0f/reqHeight);
- inSampleSize = Math.max(widthRadio, heightRadio);
- }
- return inSampleSize;
- }
- private class ImageSize{
- int width;
- int height;
- }
- private class ImgBeanHolder {
- Bitmap bm;
- String path;
- ImageView imageView;
- }
- }
Android list加载图片工具类的更多相关文章
- android异步加载图片并缓存到本地实现方法
图片过多造成内存溢出,这个是最不容易解决的,要想一些好的缓存策略,比如大图片使用LRU缓存策略或懒加载缓存策略.今天首先介绍一下本地缓存图片 在android项目中访问网络图片是非常普遍性的事 ...
- android listview 加载图片错乱(错位)
写道 今天晚上一个朋友介绍我看了一篇文章,也是解决android中listview在加载图片错位的问题,看了之后,感觉写的很好,自己也遇到这个问题,但是又不知道从何下手,看到这篇文章后,我的问题 ...
- Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果
Android Glide加载图片时转换为圆形.圆角.毛玻璃等图片效果 附录1简单介绍了Android开源的图片加载框架.在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬 ...
- 演化理解 Android 异步加载图片(转)
演化理解 Android 异步加载图片(转)http://www.cnblogs.com/CJzhang/archive/2011/10/20/2218474.html
- Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅
Android 高手进阶(21) 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明出处http://blog.csdn.net/xiaanming/article/details ...
- android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存
经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目 Android-Universal-Image-Loader 或者 ignition 都是个很好的选择. 在这里把原来 ...
- 实例演示Android异步加载图片
本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...
- 实例演示Android异步加载图片(转)
本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...
- [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html 这个可以实现ImageView异步加载 ...
随机推荐
- Entity Framework Code-First(9):DataAnnotations
DataAnnotations in Code-First: EF Code-First provides a set of DataAnnotation attributes, which you ...
- Linux的.run文件简单制作
run程序安装包实质上是一个安装脚本加要安装的程序,如下图所示: |-----------------|| || 安装脚本 || ||-----------------|| || 程序 || ||-- ...
- 对Json的一些理解
标准json格式:{"name":"王大昭","url":"https://www.cnblogs.com/codezhao/&q ...
- sqlserver2012——触发器
触发器:是一个修改指定数据时执行的存储过程. 创建触发器 Create Trigger trigger_name ON {table|view} { } 例子: insert触发器: create T ...
- EIP权限工作流平台总结-3后端框架
1.预览地址:www.eipflow.com (1) 权限工作流:www.demo.eipflow.com/Account/Login (2) 基础权限版:www.auth.eipflow.com/A ...
- 剑指Spring源码(三)俯瞰Spring的Bean的生命周期(大众版)
距离上一次写Spring源码解析,已经过去了快要好几个月了,主要原因还是Spring的源码解析类文章太难写了,不像我先前写的什么CAS源码,AQS源码,LinkedBlockingQueue等等,这些 ...
- UPC11073(DP,思维)
#include<bits/stdc++.h>using namespace std;long long dp[507][507];const long long mod = 998244 ...
- Node.js 内置模块crypto加密模块(4) Diffie Hellman
Diffie-Hellman( DH ):密钥交换协议/算法 ( Diffie-Hellman Key Exchange/Agreement Algorithm ) 百科摘录: Diffie-Hell ...
- 浏览器Quirksmode(怪异模式)与标准模式
由于历史的原因,各个浏览器在对页面的渲染上存在差异,甚至同一浏览器在不同版本中,对页面的渲染也不同.在W3C标准出台以前,浏览器在对页面的渲染上没有统一规范,产生了差异(Quirks mode或者称为 ...
- Python Day22
Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 1.创建Form类 ...