2021年9月18日 星期六

Android memory accessibility

Android這十年來跟ios比一直有痛點,就是感覺比較容易crash,除了天生上java遇到null就是crash之外,另一個就是早期Android在設計的時候,針對記憶體存取,設計了一個看起來能讓許多app能跑在android上一個不錯的機制,可惜的是眾多developers並沒有遵守這個原則去開發。就是Activity state。

https://developer.android.com/topic/libraries/architecture/saving-states
https://developer.android.com/guide/components/activities/activity-lifecycle#asem



這個設計的用意是,當app在前景時,記憶體隨你用,當然你用到炸你app一樣crash。只是當你app進背景後,android會幫你保持activity/fragment stack而保持gc的權力,這樣下一個被launch的app依舊有full system的memory可以使用。當user又回到你的app時,整個stack/state馬上被resume。快速的回到你當初app的狀態。


用兩個平台對於進背景的app的不同來解釋這個機制。

ios,進背景後,application被系統回收,下次resume app後就從頭重新launch,一切都是fresh new。

android,進背景後,允許你存資料進state,依照系統對記憶體的需求回收你的activity and fragment,甚至singleton,回來以後只要application還沒被回收,你會被系統重新re-create last state,也就是說你當下在哪一頁系統就幫你把activity, fragment stack全都延續並且顯示最後一頁,如果你用來render UI的data不存在並且你沒有有效的fetch方式,app自然直接crash。所以後期android在某一版後終於也受不了,在系統層直接做了一個保護,當你的app crash後幫你重新launch app,保護了開發者們沒注意到的東西,但還是會有系統上的風險。




說的容易做的難,我本身已經有10+ app開發經驗了,我只能說目前只做了兩個uncrashable android app,剛好也只有這兩個android從0->1開始設計,第一個是幫axiata home pow做的android TV launcher,看起來應該是有個幾百萬使用者以及還在線,但是那個只是硬需。不會crash的方式就是資料全落地,所有的epg, channel, program全都在local資料庫,所有的UI rendering都depend on those data。每一頁都只要簡單的保持uid就能從資料庫中重新fetch當時最後的data,一切都很簡單,一切都很完美,這也是android後期一直在推崇你資料就落地,幾乎大部分的大app也都照做的。

第二個app,很遺憾,那個是neo bank的app,資料落地幾乎是死罪🤣。我也沒想過工作十年後又要回到十年前做的法,資料都得保持在記憶體,哈哈哈。不能用就不能用,那就是回到十年前android一開始的設計,把資料的保持用Saved instance state來作。不得不說真的很痛苦,每一頁activity,每一頁fragment都要寫functions,protocol來連接那個state,非常的unpractical。

好險當時我有七~八個志同道合的隊員,對於這個記憶體的保護很有堅持跟理想,在不斷的sprint遞疊跟演進後,我們發現了viewmodel有個stateviewmodel
https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate

在此應該要先前情提要一下,當時那app是2019年尾開始開發,整個architecture都是用最新的jetpack mvvm,以至於後來這個stateviewmodel出來以後,我們當時每一頁activity,fragment用來保持state的那些functions,protocol全都不用寫了!stateviewmodel他就有能力保持他的記憶體配合Saved instance state,如此一來,拿爛手機的users們,不會轉帳到一半切換到其他app查轉出帳號,回來這個neo bank app後,整個記憶體被回收剛剛輸入過的資料全部規零,甚至crash得重新登入🤣

這就是整個android記憶體的故事了,十年來有著這些的故事,以及我知道目前市面上應該還是大部分的android dev都還不知道這些事情,或者知道了也不知道怎樣的architecture才能有效的解決android記憶體使用的問題。只能怪當初設計android的人太聰明(?)了,導致這十年來沒有太多android dev follow當時他們的想法。

很遺憾這篇不會有implementation detail。

甚至更精采的,可以參考sharedviewmodel,如果你有傳值的煩惱。


Ref.

https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate

https://developer.android.com/topic/libraries/architecture/saving-states

https://developer.android.com/guide/components/activities/activity-lifecycle#asem