当你的才华还撑不起你的梦想时,你只能一直前进!

【开源毕设】一款精美的家校互动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,转载请珍惜作者的劳动成果,谢谢。

posted @ 2016-11-30 10:49  南尘  阅读(3397)  评论(17编辑  收藏  举报

写不完的矫情,做不完的开源

点击进入我的GitHub页
南 尘
主 页
优美钢琴曲合集-南尘.mp3                    感谢您阅读我的博客,如果您现在工作、学习累了或者疲惫了,不妨聆听一下音乐,它能够减轻你的疲劳,还能够带给您一种舒适愉悦的心情。(样式取自博客园-欲泪成雪)