先上效果图:

如图,android默认也有Gallery,很多软件在调用时,都是使用自己的Gallery,一方面好维护,另外一方面可以做优化。要做成以上样式,图片加载类起至关重要,一不小心,就好OOM, 下面这个类就是做Gallery的核心。

package com.example.gallery.utils;import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
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.LayoutParams;
import android.widget.ImageView;public class ImageLoader {public static ImageLoader mInstance;private LruCache<String, Bitmap> mLruCache;private ExecutorService mThreadPool;private static final int DEFAULT_THREAD_POOL_SIZE = 1;private Type mType = Type.LIFO; //队列的调度方式private LinkedList<Runnable> mTaskQueue;  //任务队列,可以从头部和尾部取对象,链表不用连续的内存private Thread mPoolThread; //后台轮询线程private Handler mPoolThreadHandler;private Handler mUIHandler; //UI线程private Semaphore mSemaphorePoolThreadHandler = new Semaphore(0); //信号量用来同步,默认申请0private Semaphore mSemaphoreThreadPool;public enum Type {FIFO,LIFO;}private ImageLoader(int threadCount, Type type) {init(threadCount, type);}private void init(int threadCount, Type type) {//后台轮询线程mPoolThread = new Thread() {@Overridepublic void run() {Looper.prepare();mPoolThreadHandler = new Handler(){public void handleMessage(android.os.Message msg) {//线程池去取出一个任务进行执行mThreadPool.execute(getTask());try {mSemaphoreThreadPool.acquire(); //阻塞住} catch (InterruptedException e) {e.printStackTrace();}};};mSemaphorePoolThreadHandler.release();//释放信号量Looper.loop();};};mPoolThread.start();//获取我们应用的最大可用内存int maxMemory = (int) Runtime.getRuntime().maxMemory();int cacheMemory = maxMemory / 8;mLruCache = new LruCache<String, Bitmap>(cacheMemory){protected int sizeOf(String key, Bitmap value) {return value.getRowBytes() * value.getHeight();};// 每行的字节数*高度};//创建线程池mThreadPool = Executors.newFixedThreadPool(threadCount);mTaskQueue = new LinkedList<Runnable>();mType = type;mSemaphoreThreadPool = new Semaphore(threadCount);}public static ImageLoader getInstance(int size, Type type) {if(mInstance == null) {//效率的提升,如果多个线程进入时synchronized (ImageLoader.class) {if(mInstance == null) { // 每次都new ,会产生多个对象mInstance = new ImageLoader(DEFAULT_THREAD_POOL_SIZE, Type.LIFO);}}}return mInstance;}public void loadImage(final String path, final ImageView image) {image.setTag(path);//防止多次复用if(mUIHandler == null) {mUIHandler = new Handler() {public void handleMessage(android.os.Message msg) {//获取得到图片,为image回调设置图片ImageBeanHolder holder = (ImageBeanHolder) msg.obj;Bitmap bm = holder.bitmap;ImageView imageview = holder.image;String path = holder.path;//将path与getTag存储路径进行比较if(imageview.getTag().toString().equals(path)) {imageview.setImageBitmap(bm);}};};}Bitmap bm = getBitmapFromLruCache(path);if (bm != null) {refreshBitmap(path, image, bm);} else {addTask(new Runnable() {@Overridepublic void run() {//加载图片//图片的压缩//1.获得图片需要显示的大小ImageSize imageViewSize = getImageViewSize(image);//2.压缩图片Bitmap bm = decodeSampleBitmapFromPath(path, imageViewSize.width, imageViewSize.height);//3.把图片加入到缓存addBitmapToLruCache(path,bm);//4.进行回调refreshBitmap(path, image, bm);mSemaphoreThreadPool.release(); //任务完成,就施放信号量}});}}//从任务队列中取任务private Runnable getTask() {if(mType == Type.FIFO) {return mTaskQueue.removeFirst();} else if(mType == Type.LIFO) {return mTaskQueue.removeLast();}return null;}private void refreshBitmap(final String path, final ImageView image, Bitmap bm) {Message msg = Message.obtain();ImageBeanHolder holder = new ImageBeanHolder();holder.bitmap = bm;holder.image = image;holder.path = path;msg.obj = holder;mUIHandler.sendMessage(msg);}//将图片加到LruCacheprivate void addBitmapToLruCache(String path, Bitmap bm) {if(getBitmapFromLruCache(path) == null) {if(bm != null) {mLruCache.put(path, bm);}}}private ImageSize getImageViewSize(ImageView image) {ImageSize imageSize = new ImageSize();DisplayMetrics displayMetrics = image.getContext().getResources().getDisplayMetrics();LayoutParams layoutParams = image.getLayoutParams();int width = image.getWidth(); //获取实际宽度
//        int width = getImageViewFiledValue(image, "mMaxWidth");//layoutParams.width == LayoutParams.WRAP_CONTENT ? 0 :if(width <= 0) { //wrap_content -1 fill_parent -2width = layoutParams.width; //获取image在layout中声明的宽度}if(width <= 0) { width = getImageViewFiledValue(image, "mMaxWidth"); //检查最大值}if(width <= 0) { width = displayMetrics.widthPixels;//为屏幕的宽度}int height = image.getHeight(); //获取实际高度//layoutParams.width == LayoutParams.WRAP_CONTENT ? 0 :if(height <= 0) { //wrap_content -1 fill_parent -2height = layoutParams.height; //获取image在layout中声明的高度}if(height <= 0) { height = getImageViewFiledValue(image, "mMaxHeight"); //检查最大值}if(height <= 0) { height = displayMetrics.heightPixels;//为屏幕的高度}imageSize.height = height;imageSize.width = width;return imageSize;}//为什么用反射,因为检查最大值是API 16才能用,兼容API 8 时,就用反射private static int getImageViewFiledValue(Object object,String fieldName) {int value = 0;try {Field field = ImageView.class.getDeclaredField(fieldName);field.setAccessible(true);int fieldValue = field.getInt(object);if(fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {value = fieldValue;}} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();}return value;}//根据显示的宽和高对图片进行压缩private Bitmap decodeSampleBitmapFromPath(String path, int width, int height) {//获取图片的宽和高,并不把图片加载到内存中BitmapFactory.Options  options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, options);options.inSampleSize = caculateInSampleSize(options, width, height);options.inJustDecodeBounds = false; //把图片加载到内存中Bitmap bitmap = BitmapFactory.decodeFile(path, options);//已经进行压缩return bitmap;}private int caculateInSampleSize(Options options, int reqWidth, int reqHeight) {int width = options.outWidth;int height = options.outHeight;int inSampleSize = 1;if(width > reqWidth || height > reqHeight) {int widthRadio = Math.round(1.0f * width / reqWidth);int heightRadio = Math.round(1.0f * width / reqHeight);inSampleSize = Math.max(widthRadio, heightRadio);}return inSampleSize;}private synchronized void addTask(Runnable runnable) {mTaskQueue.add(runnable);
//        if(mPoolThreadHandler == null)
//            wait();try {if(mSemaphorePoolThreadHandler == null) mSemaphorePoolThreadHandler.acquire();} catch (InterruptedException e) {e.printStackTrace();}mPoolThreadHandler.sendEmptyMessage(0x110); //发送通知}private Bitmap getBitmapFromLruCache(String key) {return mLruCache.get(key);}private class ImageSize {int width;int height;}private class ImageBeanHolder{ //防止错乱Bitmap bitmap;ImageView image;String path;}
}

做自己的软件的Gallery(一)相关推荐

  1. 老程序员的忠告:不要做浮躁的软件工程师

    老程序员的忠告:不要做浮躁的软件工程师: 每天读一遍,思考一下:我是否浮躁? 1.不要看到别人的回复,第一句话就说:给个代码吧!你应该想想为什么.当你自己想出来再参考别人的提示,就会知道自己和别人思路 ...

  2. 学习编程做笔记的软件_可以在图片上做笔记的软件

    做笔记是一个很好的工作和学习方式,通过做笔记,可以让我们记录下来自己接触到的知识,同时在记笔记的时候还可以引发更深刻的思考.在以前,大家提到笔记的时候,脑海里都是文字的形式,但是随着科技的发展,声音图 ...

  3. 语言做一个自动售货机软件_软件开发手机app系统软件高端定制做一个app软件要多少钱...

    软件开发手机app系统软件高端定制-做一个app软件要多少钱 APP开发分原生APP开发和在线制作,我们来看下这两种都需要多少费用吧. 1.原生APP开发(定制开发) 互联网是个神奇的大网,大数据开发 ...

  4. 用计算机电脑怎么做ppt软件,电脑做ppt的软件叫什么

    电脑做ppt的软件叫什么 电脑做ppt的软件叫PowerPoint,大家习惯简称ppt.用户可以通过投影进行要演示的ppt.ppt在我们工作中是非常常见的,是办公文员必须学会的'一项技能.下面就针对这 ...

  5. 推荐三款适合学生做笔记的软件

    "好记性不如烂笔头",这是我们从小听到大的俗语,也是古人对学习方法的总结.确实,做笔记是学习过程中绕不开的话题. 在中小学阶段,做笔记主要以老师所认为的要点进行重复摘抄和记忆为主. ...

  6. 北京专业做大数据软件开发的公司排名有哪些

    北京专业做大数据软件开发的公司排名有哪些 大数据开发是目前大多数软件开发程序员都在学习的一个互联网编程技术,下面我们就通过案例分析来了解一下,大数据开发都需要掌握哪些技术知识. 一线 华盛恒辉.五木恒 ...

  7. 做对日软件外包项目的体会

    很多同行都在抱怨对日外包项目的技术含量低,从项目中学不到东西,得不到提高.其实这是一种不成熟的表现,无论是外包项目或其他的什么项目,单纯的依靠学项目中技术点来提高自己,那进步的速度就可以和蜗牛相比,试 ...

  8. 有什么做GIF的软件?这3款APP超酷炫

    有什么做GIF的软件?喜欢聊微信的你们都有这种感觉吧:聊天的时候,大部分情况下都是动态图片比静态图片更能表达情绪.经常会看到一张有意思的动态图片后,像中了魔一样反复观看,说不定还会嘻嘻嘻地笑出声来吓到 ...

  9. 做个自动化软件拿来办公、刷副本、回微信 | 源码公开,开箱即用

    写在最开始的话: 看了B站一个up主的讲解之后尝试自己动手实现了一下.下面是源视频地址 .得到作者的同意分享出来. 5分钟,教你做个自动化软件拿来办公.刷副本.回微信 | 源码公开,开箱即用_哔哩哔哩 ...

  10. 一个计算机爱好者的不完整回忆(三十三)做过的软件

    由于写这个不完整回忆,忽然想看看自己到底编过多少软件.前天出差回家(我最近被外派大连工作,所以回本地工作反而算作出差),到自己老电脑上看了看,发现原来的VB5和VB6留下的软件代码并没有多少. 先统计 ...

最新文章

  1. Spring学习总结(7)——applicationContext.xml 配置文详解
  2. Qt开发,图文详解Hello World全过程
  3. Bootstrap 3: 菜单居中 Center content in responsive bootstrap navbar
  4. 使用FastReport报表工具生成图片格式文档
  5. 编程范式之命令式与函数式
  6. SpringBoot2.0之七 实现页面和后台代码的热部署
  7. IDEA出现Module ** must not contain source root **. The root already belongs to module **这类错误的解决方法
  8. 2014 传播一点正能量
  9. Bind服务简单应用之一(介绍)
  10. SQL 查询所有表名、字段名、类型、长度、存储过程、视图
  11. composer killed while updating or install
  12. ElasticSearch5.0——IK词库加载
  13. 【Python百日进阶-Web开发-Feffery】Day315 - fac导航4:AntdDropdown下拉菜单
  14. 并发之Striped64(l累加器)
  15. 计算机是如何存储数字的?
  16. android低电量提示,Android P系统低电量提醒功能 根据使用情况判断充电时间
  17. 元宇宙的前景及四大赛道
  18. PostGIS开发实例之农村土地确权数据库实例
  19. 科技社计算机部长竞选演讲稿,计算机*组长竞聘演讲稿范文
  20. 2021年中国后座椅信息娱乐市场趋势报告、技术动态创新及2027年市场预测

热门文章

  1. 论文笔记_S2D.10-2016-NIPS_室外单张图像的深度感知
  2. 从零开始搭二维激光SLAM --- Karto的后端优化与回环检测功能对比测试与分析
  3. cartographer探秘第四章之代码解析(一) --- SLAM处理过程 --- 文章索引
  4. 【直观详解】信息熵、交叉熵和相对熵
  5. Hadoop学习笔记(五):MapReduce的类型与格式
  6. C++中vector的用法
  7. Mongodb的oplogsize修改
  8. DataFactory插入MySQL中文乱码问题
  9. html5介绍 之亮点特性
  10. TListView列表拒绝添加重复信息