【开源毕设】一款精美的家校互动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值呢?可以通过下面的方法,动态计算。
/**
* @description 计算图片的压缩比率
*
* @param options 参数
* @param reqWidth 目标的宽度
* @param reqHeight 目标的高度
* @return
*/
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// 源图片的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
然而,事实却不如我们想象那么美好,inSampleSize官方注释告诉我们一个必须注意的点:因为inSampleSize只能是2的整数次幂,意味着如果上面我们算出来inSampleSize为6的话,这时候只能向下取得整数次幂,就是4。这样设计的原因很可能是为了渐变bitmap压缩,毕竟按照2的次方进行压缩会比较高效和方便。
那遇上这样的问题,肯定是无法达到我们想要的效果的,比如我们计算出来的inSampleSize是15,向下取就成了8,明显差距太大。那有没有一种方法达到我们的效果呢?
答案是肯定的!
5)再次压缩
别忽略了Bitmap有这么一个方法:createScaleBitmap!!
这个方法可以给我们按照要求拉伸/缩小一个bitmap,我们可以通过这个方法把我们之前得到的较大的缩略图进行缩小,让其完全符合我们的需求。
/**
* @description 通过传入的bitmap,进行压缩,得到符合标准的bitmap
*
* @param src
* @param dstWidth
* @param dstHeight
* @return
*/
private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {
//如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。
if (inSampleSize % 2 == 0) {
return src;
}
// 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false
Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
if (src != dst) { // 如果没有缩放,那么不回收
src.recycle(); // 释放Bitmap的native像素数组
}
return dst;
}
或许你会问,为啥要先从inSampleSize产生一个缩略图A,而不直接通过createScaseBitmap()方法缩放呢?
因为如果要从原始的图片直接缩放的话,就需要把原始图片直接放入内存 中,这将十分危险!!!先通过inSmapleSize得到一个较大的缩略图,它会比原图小很多,直接加载到内存中再进行拉伸/缩小就比较安全了!
6)完整代码:
package com.example.nanchen.aiyaschoolpush.utils; import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory; /**
*
* bitmap相关操作工具类
*
* @author nanchen
* @fileName AiYaSchoolPush
* @packageName com.example.nanchen.aiyaschoolpush.utils
* @date 2016/11/28 09:45
*/ public class BitmapUtil { /**
* @description 计算图片的压缩比率
*
* @param options 参数
* @param reqWidth 目标的宽度
* @param reqHeight 目标的高度
* @return
*/
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// 源图片的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
} /**
* @description 从Resources中加载图片
*
* @param res
* @param resId
* @param reqWidth
* @param reqHeight
* @return
*/
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高
BitmapFactory.decodeResource(res, resId, options); // 读取图片长款
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 调用上面定义的方法计算inSampleSize值
// 使用获取到的inSampleSize值再次解析图片
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图
return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); // 进一步得到目标大小的缩略图
} /**
* @description 通过传入的bitmap,进行压缩,得到符合标准的bitmap
*
* @param src
* @param dstWidth
* @param dstHeight
* @return
*/
private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {
//如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。
if (inSampleSize % 2 == 0) {
return src;
}
// 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false
Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
if (src != dst) { // 如果没有缩放,那么不回收
src.recycle(); // 释放Bitmap的native像素数组
}
return dst;
} /**
* @description 从SD卡上加载图片
*
* @param pathName
* @param reqWidth
* @param reqHeight
* @return
*/
public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeFile(pathName, options);
return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize);
}
}
六、写在最后
好哒,第三期就介绍到这里啦,喜欢的话就去github下载下来体验吧~(PS:楼主服务器目前是采用xampp搭建的本地服务器,外网暂无法访问,需要体验效果请自行搭建服务器,见楼主前面博客:【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~)
github地址:https://github.com/nanchen2251/AiYaSchoolPush
开源不易,别忘了点点推荐,点点star,转载请珍惜作者的劳动成果,谢谢。
【开源毕设】一款精美的家校互动APP分享——爱吖校推 [你关注的,我们才推](持续开源更新3)附高效动态压缩Bitmap的更多相关文章
- 【毕业设计】基于Android的家校互动平台开发(内含完整代码和所有文档)——爱吖校推(你关注的,我们才推)
☆ 写在前面 之前答应大家的毕业答辩之后把所有文档贡献出来,现在答辩已过,LZ信守承诺,把所有文档开源到了GitHub(这个地址包含所有的代码和文档以及PPT,外层为简单的代码).还望喜欢的朋友们,不 ...
- 15款精美的 WordPress 电子商务网站模板
在这篇文章中,我们收集了15款精美的 WordPress 电子商务网站模板.WordPress 作为最流行的博客系统,插件众多,易于扩充功能.安装和使用都非常方便,而且有许多第三方开发的免费模板,安装 ...
- 分享8款精美的jQuery图片播放插件
本文将和大家一起分享8款精美的jQuery图片播放插件,每一款插件均有演示和源码下载,有兴趣的朋友可以下载使用和研究.废话不多说了,直接上这些插件. 1.3D轮播相册 这款3D相册插件利用了HTML5 ...
- 8款精美的HTML5图片动画分享
From:http://geek.csdn.net/news/detail/196250 HTML5结合jQuery可以让网页图片变得更加绚丽多彩,比如实现一些图片3D切换.CSS3动画绘制以及各种图 ...
- Airtest网易开源的一款UI自动化测试工具
Airtest网易开源的一款UI自动化测试工具 1 Airtest 简介Airtest Project是网易游戏内部工具团队开发并开源的一款UI自动化测试工具,据说曾经获得谷歌力挺. AirtestI ...
- 开源!一款功能强大的高性能二进制序列化器Bssom.Net
好久没更新博客了,我开源了一款高性能的二进制序列化器Bssom.Net和新颖的二进制协议Bssom,欢迎大家Star,欢迎参与项目贡献! Net开源技术交流群 976304396,禁止水,只能讨论技术 ...
- 18款js和jquery文字特效代码分享
18款js和jquery文字特效代码分享 jQCloud标签云插件_热门城市文字标签云代码 js 3d标签云特效关键词文字球状标签云代码 原生JS鼠标悬停文字球状放大显示效果代码 原生js文字动画圆形 ...
- 美了美了!22款精美的 iOS 应用程序图标模板
22款制作精美的 iOS 应用程序图标设计作品,遵循图形设计的现代潮流,所有图标都非常了不起,给人惊喜.通过学习这些移动应用程序图标,设计人员可以提高他们的创作,使移动用户界面看起来更有趣和吸引人. ...
- 开源的49款Java 网络爬虫软件
参考地址 搜索引擎 Nutch Nutch 是一个开源Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. Nutch的创始人是Doug Cutting, ...
随机推荐
- Angular2入门系列教程2-项目初体验-编写自己的第一个组件
上一篇 使用Angular-cli搭建Angular2开发环境 Angular2采用组件的编写模式,或者说,Angular2必须使用组件编写,没有组件,你甚至不能将Angular2项目启动起来 紧接着 ...
- JAVA for mac 的学习之路
要学习一门新技术,首先得下载相关的工具. 一 . 下载相关工具 1. 下载 jdk formac 下载地址为:http://www.oracle.com/technetwork/java/javase ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- [APUE]标准IO库(下)
一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中 ...
- MVC常遇见的几个场景代码分享
本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...
- 缓存工厂之Redis缓存
这几天没有按照计划分享技术博文,主要是去医院了,这里一想到在医院经历的种种,我真的有话要说:医院里的医务人员曾经被吹捧为美丽+和蔼+可亲的天使,在经受5天左右相互接触后不得不让感慨:遇见的有些人员在挂 ...
- angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用
今天我们要讲的是ng2的路由系统. 例子
- 缓存、队列(Memcached、redis、RabbitMQ)
本章内容: Memcached 简介.安装.使用 Python 操作 Memcached 天生支持集群 redis 简介.安装.使用.实例 Python 操作 Redis String.Hash.Li ...
- ResponsibleChain(责任链模式)
/** * 责任链模式 * @author TMAC-J * 老板讲任务交给CTO,CTO自然不会亲自去做,又把人物分配给项目经理,项目经理再把任务分配给组长,组长再分配给个人 * 如果中途哪个环节出 ...
- Hadoop 2.x 生态系统及技术架构图
一.负责收集数据的工具:Sqoop(关系型数据导入Hadoop)Flume(日志数据导入Hadoop,支持数据源广泛)Kafka(支持数据源有限,但吞吐大) 二.负责存储数据的工具:HBaseMong ...