? ? ?最近在重構一個視頻相關的Android App,由于是重構,所以看的角度更加上層,在擁有大多數中間件的情況下,只需要根據業務需求,將各種控件塞到一個界面中,然后,加上需要的業務邏輯,就是一個不錯的界面了。
? ? 由此,我想到把這一過程記錄下,嘗試著站在架構的角度,來分析一個App的從無到有(產品經理+程序員)。如果以后接到類似的業務,可以迅速的進行"整體---局部"的切換,跳出各種細節的泥潭。
一個界面
? ? 以這樣一個單獨的界面進行分析,他的業務邏輯如下:
? ? 用戶已經在上一個頁面剪輯出了一段視頻,在這個頁面為剪輯出的視頻添加分類,標題,選擇封面,然后上傳到服務器。
? ? 用戶進入到該界面的時候,可以拿到之前剪輯的視頻流(內存中),或者是一個本地視頻的地址。然后,利用開源工具掃描出視頻中的關鍵幀,作為封面供用戶選擇,用戶選擇的封面只能是顯示出來的關鍵幀。當用戶選擇完封面后,手指釋放,界面的背景圖也會變成用戶剛剛選擇的封面。
? ? 這個頁面在Android中的呈現是一個Activity,在這個頁面被創建出來的時候,我要
1. 將基礎控件都渲染出來(有些控件必須有從服務端獲取的數據才可以顯示)
2.從網絡加載數據(如分類,標簽等數據)
? ? 接下來就是具體的事情,將底部的封面圖顯示出來,那么我創建一個自定義View,然后通過開源庫將視頻的關鍵幀截取并壓縮,自定義View將縮略圖繪制出來。
? ? "將視頻的關鍵幀截取出來",這個操作,可以放在Activity中執行,也可以放在自定義View中執行。
方式一:
? ? 利用MVC的思想,將業務放在Controller(Activity)中,View只負責將提取出的Bitmap壓縮,然后繪制出來,這樣也可以提高耦合性。
? ? 采用這樣一種方式的話,整個Bitmap集合在Activity中只有一份,子線程所做的就是將生成的bitmap添加到集合中,然后讓自定義View把集合中的bitmap壓縮并繪制出來(UI線程中)。
問題 1:為什么不在子線程中完成壓縮工作?
答:圖片壓縮需要根據自定義View的寬高決定,在Activity中無法準確的知道自定義View的寬高。
方式二:
? ? 將提取以及壓縮工作放在自定義View中,在其onLayout()方法執行后(此時已知道width和height),開啟一個子線程提取關鍵幀并壓縮,然后在onDraw()中將縮略圖繪制出來。
? ? 此時將原始的關鍵幀集合放在了Activity中,因為背景圖是原始的bitmap,在創建自定義View后,將視頻的路徑和cover集合傳遞過去,View中的子線程所需要做的就是填充這個cover集合,然后生成一個縮略圖集合--thumbNail,并將其繪制出來。
資源的回收
? ? 當View中存在子線程和Bitmap集合時,我們需要注意到內存泄露的問題,當View被銷毀時,我們要確保子線程不再執行,bitmap被回收。
同樣,在Activity中也要做同樣的處理,當Activity被銷毀時,所有的資源也應該被釋放。
總結
? ? 有時候,站在內存的角度來設計這個頁面,能使代碼變得簡潔,思路更加清晰。
? ? 對于單一的頁面,在設計的時候要確保資源不要過多的冗余,根據頁面就可以將資源定義出來,如字符串集合,bitmap集合,子線程,task任務等等。在界面被銷毀的時候,要確保之前開啟的資源被釋放(站在內存的角度),啟動資源就是分配內存,關閉資源就是回收內存。