1、寫在前面php
愛吖校推如同它的名字同樣,是一款校園類信息推送交流平臺,這麼多的家校互動類軟件,你選擇了我,這是個人幸運。
從第一次在博客園上寫博客到如今,我一次一次地提升博文的質量和代碼的可讀性,都是爲了大家,由於有大家,纔有我。 我從一個一個的demo到從0開始作這個app,一路歷經艱難險阻,期待你與我進行心靈交流。由於我也曾遇到各類棘手的問題,處處詢問不到答案, 那個時候的我,也許正如如今的你。而我,也還在這條道路上默默前行。html
前面兩期地址:【開源畢設】一款精美的家校互動APP分享——愛吖校推 [你關注的,咱們才推](持續開源更新)前端
【開源畢設】一款精美的家校互動APP分享——愛吖校推 [你關注的,咱們才推](持續開源更新2)android
小夥伴們,寶寶又來了,是的,愛吖校推又實現了新功能,此次給你們帶來的是什麼呢?此次是客服系統,推送系統和圖片發送以及動態更新的功能更新,如今APP支持圖片壓縮上傳,採用eventbus動態刷新UI,而且同一個圈子的人能收到相應人員發送的消息動態啦!!對,不只是android,php服務器也相應獲得了更新,還在猶豫什麼?快下載看看吧~git
2、一樣的有用之處程序員
1)經過本項目你能夠拿到你想要的自定義控件效果;github
2)android純前端程序員也能瞭解到如何用php編寫api接口,讓項目數據動起來;api
3)有意轉後臺的程序員能夠學到更多邏輯方面有用的知識;數組
4)對,若是你是初學者,你可能會獲得一位前行良友;緩存
5)玩什麼遊戲,安心擼代碼吧!
6)對,這不僅是android,這不僅是php,這還有文檔,沒錯,就是開源!!!
7)圖片佔用內存泄漏?這裏有手把手教你封裝的bitmapUtil。
3、上個效果圖唄
4、下一步要作的
1)加入微信小視頻功能
2)優化演示圖中出現的內存泄漏
3) 減少資源體積
5、幫你們安利一下開發必過的坑——圖片經常致使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 }
6、寫在最後
好噠,第三期就介紹到這裏啦,喜歡的話就去github下載下來體驗吧~(PS:樓主服務器目前是採用xampp搭建的本地服務器,外網暫沒法訪問,須要體驗效果請自行搭建服務器,見樓主前面博客:【定有驚喜】android程序員如何作本身的API接口?php與android的良好交互(附環境搭建),讓前端數據動起來~)
github地址:https://github.com/nanchen2251/AiYaSchoolPush
開源不易,別忘了點點推薦,點點star,轉載請珍惜做者的勞動成果,謝謝。