热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【开源毕设】一款精美的家校互动APP分享——爱吖校推[你关注的,我们才推](持续开源更新3)附高效动态压缩Bitmap

一、写在前面爱吖校推如同它的名字一样,是一款校园类信息推送交流平台,这么多的家校互动类软件,你选择了我,这是我的幸运。从第一次在博客园上写博客到现在,我一次一次地提高博文的质量和代码的可读性,

一、写在前面

  爱吖校推如同它的名字一样,是一款校园类信息推送交流平台,这么多的家校互动类软件,你选择了我,这是我的幸运。
从第一次在博客园上写博客到现在,我一次一次地提高博文的质量和代码的可读性,都是为了你们,因为有你们,才有我。 我从一个一个的demo到从0开始做这个app,一路历经艰难险阻,期待你与我进行心灵交流。因为我也曾遇到各种棘手的问题,到处询问不到答案, 那个时候的我,也许正如现在的你。而我,也还在这条道路上默默前行。

  前面两期地址:【开源毕设】一款精美的家校互动APP分享——爱吖校推 [你关注的,我们才推](持续开源更新)

         【开源毕设】一款精美的家校互动APP分享——爱吖校推 [你关注的,我们才推](持续开源更新2)

  小伙伴们,宝宝又来了,是的,爱吖校推又实现了新功能,这次给大家带来的是什么呢?这次是客服系统,推送系统和图片发送以及动态更新的功能更新,现在APP支持图片压缩上传,采用eventbus动态刷新UI,并且同一个圈子的人能收到相应人员发送的消息动态啦!!对,不仅是android,php服务器也相应得到了更新,还在犹豫什么?快下载看看吧~

二、同样的有用之处

  

  1)通过本项目你可以拿到你想要的自定义控件效果;

  2)android纯前端程序员也能了解到如何用php编写api接口,让项目数据动起来;

  3)有意转后台的程序员可以学到更多逻辑方面有用的知识;

  4)对,如果你是初学者,你可能会得到一位前行良友;

  5)玩什么游戏,安心撸代码吧!

  6)对,这不只是android,这不只是php,这还有文档,没错,就是开源!!!

  7)图片占用内存泄漏?这里有手把手教你封装的bitmapUtil。

三、上个效果图呗

      

四、下一步要做的

  1)加入微信小视频功能

  2)优化演示图中出现的内存泄漏

  3) 减小资源体积

五、帮大家安利一下开发必过的坑——图片常常导致OOM

  1)大家一定都知道,手机相机拍照的图片都是几千像素的,而我们的手机屏幕却一般是720的,并且一张大图,动则几M,上传起来用户流量着实受不了,那么压缩资源体积就变得相当麻烦了,这里就给大家讲解一下压缩上传的正确姿势。

 

  2)我相信作为coder的你,一定知道Bitmap是引起OOM的罪魁祸首之一,所以我们一定为了节约内存,一般都会在服务器上缓存一个缩略图,这样不但可以提升下载速度,减少用户流量,还达到了很好的节约内存的目的。

  要是我们能把bitmap设置为imageView的大小,根据要显示的ImageView来压缩Bitmap那肯定最好了。

  根据这样的思路,我们肯定得首先算出imageView的宽高,这个很简单;直接imageView.getWidth()和imageView.getHeight()方法就可以达到目的。

  3)如果你操作图片,你一定知道BitmapFatory,因为我们通常使用它来操作图片。

     BitmapFactory这个类提供了多个解析方法(decodeByteArray,decodeFile,decodeResource等)用来创建bitmap对象,其中sd卡图片用decodeFile,传入path路径和Options就可以了,而网络图片我们通常使用decodeStream方法,资源文件采用decodeResource;

    然而这些方法,都会为bitmap分配内存,图片太大一定会导致OOM的,所以我们需要先进行压缩,使用BitmapFatory.Options。

  4)BitmapFactory.Options碎碎念

    它有一个inJustDecodeBounds属性,当这个属性为true的时候,调用上面三个方法返回的就不是一个完整的bitmap对象,而是null。因为它禁止这些方法为bitmap分配内存,当时设置这个属性为true的时候,Options的outWidth,outHeight和outMimeType属性就会被复制。这样我们就可以在加载图片之前获取到图片的长宽和MIME类型。就等于不读取这个图片,却获取到了它的参数,的确很6。

    说到这里,必须说到一个很6的属性了,inSampleSize,可以理解为压缩比率,设置好这个比率,就能调用上面的decodeXXXX方法获得缩略图了,如果图片大小都一致,那还可以定死它,可我们的图片却大小不一,那我们应该如何获得正确的inSampleSize值呢?可以通过下面的方法,动态计算。

 1   /**
 2      * @description 计算图片的压缩比率
 3      *
 4      * @param options 参数
 5      * @param reqWidth 目标的宽度
 6      * @param reqHeight 目标的高度
 7      * @return
 8      */
 9     private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
10         // 源图片的高度和宽度
11         final int height = options.outHeight;
12         final int width = options.outWidth;
13         int inSampleSize = 1;
14         if (height > reqHeight || width > reqWidth) {
15             final int halfHeight = height / 2;
16             final int halfWidth = width / 2;
17             // Calculate the largest inSampleSize value that is a power of 2 and keeps both
18             // height and width larger than the requested height and width.
19             while ((halfHeight / inSampleSize) > reqHeight
20                     && (halfWidth / inSampleSize) > reqWidth) {
21                 inSampleSize *= 2;
22             }
23         }
24         return inSampleSize;
25     }

  然而,事实却不如我们想象那么美好,inSampleSize官方注释告诉我们一个必须注意的点:因为inSampleSize只能是2的整数次幂,意味着如果上面我们算出来inSampleSize为6的话,这时候只能向下取得整数次幂,就是4。这样设计的原因很可能是为了渐变bitmap压缩,毕竟按照2的次方进行压缩会比较高效和方便。

  那遇上这样的问题,肯定是无法达到我们想要的效果的,比如我们计算出来的inSampleSize是15,向下取就成了8,明显差距太大。那有没有一种方法达到我们的效果呢?

  答案是肯定的!

  5)再次压缩

  别忽略了Bitmap有这么一个方法:createScaleBitmap!!

  这个方法可以给我们按照要求拉伸/缩小一个bitmap,我们可以通过这个方法把我们之前得到的较大的缩略图进行缩小,让其完全符合我们的需求。

  

 1 /**
 2      * @description 通过传入的bitmap,进行压缩,得到符合标准的bitmap
 3      *
 4      * @param src
 5      * @param dstWidth
 6      * @param dstHeight
 7      * @return
 8      */
 9     private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {
10         //如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。
11         if (inSampleSize % 2 == 0) {
12             return src;
13         }
14         // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false
15         Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
16         if (src != dst) { // 如果没有缩放,那么不回收
17             src.recycle(); // 释放Bitmap的native像素数组
18         }
19         return dst;
20     }

  或许你会问,为啥要先从inSampleSize产生一个缩略图A,而不直接通过createScaseBitmap()方法缩放呢?

  因为如果要从原始的图片直接缩放的话,就需要把原始图片直接放入内存 中,这将十分危险!!!先通过inSmapleSize得到一个较大的缩略图,它会比原图小很多,直接加载到内存中再进行拉伸/缩小就比较安全了!

  6)完整代码:

  1 package com.example.nanchen.aiyaschoolpush.utils;
  2 
  3 import android.content.res.Resources;
  4 import android.graphics.Bitmap;
  5 import android.graphics.BitmapFactory;
  6 
  7 /**
  8  *
  9  * bitmap相关操作工具类
 10  *
 11  * @author nanchen
 12  * @fileName AiYaSchoolPush
 13  * @packageName com.example.nanchen.aiyaschoolpush.utils
 14  * @date 2016/11/28  09:45
 15  */
 16 
 17 public class BitmapUtil {
 18 
 19     /**
 20      * @description 计算图片的压缩比率
 21      *
 22      * @param options 参数
 23      * @param reqWidth 目标的宽度
 24      * @param reqHeight 目标的高度
 25      * @return
 26      */
 27     private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
 28         // 源图片的高度和宽度
 29         final int height = options.outHeight;
 30         final int width = options.outWidth;
 31         int inSampleSize = 1;
 32         if (height > reqHeight || width > reqWidth) {
 33             final int halfHeight = height / 2;
 34             final int halfWidth = width / 2;
 35             // Calculate the largest inSampleSize value that is a power of 2 and keeps both
 36             // height and width larger than the requested height and width.
 37             while ((halfHeight / inSampleSize) > reqHeight
 38                     && (halfWidth / inSampleSize) > reqWidth) {
 39                 inSampleSize *= 2;
 40             }
 41         }
 42         return inSampleSize;
 43     }
 44 
 45     /**
 46      * @description 从Resources中加载图片
 47      *
 48      * @param res
 49      * @param resId
 50      * @param reqWidth
 51      * @param reqHeight
 52      * @return
 53      */
 54     public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
 55         final BitmapFactory.Options optiOns= new BitmapFactory.Options();
 56         options.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高
 57         BitmapFactory.decodeResource(res, resId, options); // 读取图片长款
 58         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 调用上面定义的方法计算inSampleSize值
 59         // 使用获取到的inSampleSize值再次解析图片
 60         options.inJustDecodeBounds = false;
 61         Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图
 62         return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); // 进一步得到目标大小的缩略图
 63     }
 64 
 65     /**
 66      * @description 通过传入的bitmap,进行压缩,得到符合标准的bitmap
 67      *
 68      * @param src
 69      * @param dstWidth
 70      * @param dstHeight
 71      * @return
 72      */
 73     private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {
 74         //如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。
 75         if (inSampleSize % 2 == 0) {
 76             return src;
 77         }
 78         // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false
 79         Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
 80         if (src != dst) { // 如果没有缩放,那么不回收
 81             src.recycle(); // 释放Bitmap的native像素数组
 82         }
 83         return dst;
 84     }
 85 
 86     /**
 87      * @description 从SD卡上加载图片
 88      *
 89      * @param pathName
 90      * @param reqWidth
 91      * @param reqHeight
 92      * @return
 93      */
 94     public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) {
 95         final BitmapFactory.Options optiOns= new BitmapFactory.Options();
 96         options.inJustDecodeBounds = true;
 97         BitmapFactory.decodeFile(pathName, options);
 98         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
 99         options.inJustDecodeBounds = false;
100         Bitmap src = BitmapFactory.decodeFile(pathName, options);
101         return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize);
102     }
103 }

六、写在最后

  好哒,第三期就介绍到这里啦,喜欢的话就去github下载下来体验吧~(PS:楼主服务器目前是采用xampp搭建的本地服务器,外网暂无法访问,需要体验效果请自行搭建服务器,见楼主前面博客:【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~)

  github地址:https://github.com/nanchen2251/AiYaSchoolPush

  开源不易,别忘了点点推荐,点点star,转载请珍惜作者的劳动成果,谢谢。


推荐阅读
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • HTML学习02 图像标签的使用和属性
    本文介绍了HTML中图像标签的使用和属性,包括定义图像、定义图像地图、使用源属性和替换文本属性。同时提供了相关实例和注意事项,帮助读者更好地理解和应用图像标签。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
author-avatar
mobiledu2502926527
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有