Activity間資料轉送
當對Android有一些瞭解後,不難發現,Android程式UI架構接近於Web頁面的概念。每一個用於呈現頁面的組件,Activity,都是彼此獨立的,它們通過系統核心來調度整合,彼此之間的通過Intent機制來串聯。
每一種架構都會有其利弊,Android當然也不能超然脫俗。由於Activity之間的松耦合關係,使得其複用能力特別的出色,Mash-Up方式可以有效提高開發效率。但另一方面,由於Activity過於的獨立,它們之間的資料共用,成為一個麻煩的事情。
基於訊息的傳輸
最標準的Activity之間的資料轉送,就是通過Intent的Extra對象。比如,你在A這個Activity上拿到一坨使用者輸入的文本資訊,興高采烈的想把它放到B這個Activity上展示並發送,一個很可行的方式,是通過Intent的putExtra介面,把使用者輸入的那些字元資訊,按照key/value的形式放進Intent,傳輸到B這個Activity上。
如示,從A到B的傳輸,看上去是一個直連,但其實,Intent都是要經由系統核心層去分析調度的,這個操作,跨越了進程邊界,自然而然,其中的資料,就是需要序列化和還原序列化的,而不可以僅通過一個指標就倒騰過去了。
基於這樣類訊息的傳輸模式,好處不多說,直接談問題:
- 首先,對於大資料,就是一場杯具,不可能一坨上M的資料,也來來回回的傳來傳去,慢死了誰來負責;
- 再則,Activity之間,維繫的是一種線性關係,當我想把一份資料,從隊尾一級級傳到隊頭的話,自己曆經磨難不提,會把中間所有的Activity都搭上,他們明明自己可能不需要這份資料,也得拿著擱著,為他人做嫁衣裳,不惆悵都不行;
- 此外,基於訊息的傳輸,會把同一份資料產生若干個副本,有時候,這樣很好,沒有副作用,大家自己玩自己的不需要看別人臉色,但還有些時候,你就上杆子需要把這些資料都修改一下,同步起來那就太慘烈了;
- 最後,寫序列化代碼實在是太無聊了,稍微複雜點的代碼,就要自己寫個序列化介面,整個吃力不討好的活計。
基於外部儲存的傳輸既然
獸獸
手手相傳太幸苦,自然而然的想法就是找個地方,A把資料擱在那裡,把地址資訊告訴B,B需要的話,按圖索驥,自取就好。這個擱東西的地方,可以考慮選擇
外部儲存。在Android中,預設了一些快捷便利類和模組,更好的支援不同類別資料的存取。如果,需要儲存的是一些小資料量的配置資訊,可以選擇
Preference,它等同於傳統意義上的設定檔案。Preference提供了一些基於key/value的存取介面,可以放置一些簡單的基本資料或者派生了
Parcelable介面的對象。一個很好的應用情境是
Cookie的存放。你在登入介面獲得了一份Cookie,你可以把它扔進Preference,誰想要誰去拿,再也不要來來回回的折騰了。Preference適合於小資料、設定資訊,如果大資料,你可以考慮使用
資料庫。在Android中,使用的是
Sqlite,相關的類,堆放在
android.database名字空間下,自查,無需贅述。
在Android裡,資料庫是私人的,如果想分享給第三方組件使用,就需要用ContentProvider來封裝了。比如你用系統的錄音機組件即時搞一段音頻資訊,它不是返回可能大到恐怖的錄音資料,而是會返回給你一個Uri,它標明了這份資料在ContentProvider的地址資訊,拿著這個Uri,領取資料就好。
當然當然,如果你足夠淡定,也可以用赤果果的
File來儲存。如果這個檔案存在手機私人目錄下,那就內部使用,放在SD卡上,那就可以所有應用,一切分享。
基於這樣外部儲存的資料轉送,優缺點顯而易見,它解決了困擾Intent的傳輸路徑複雜,不利於傳輸大批量資料的問題,但同時,它有留下了效率隱患,複雜了編程模型。因為面對外部儲存,開發人員必須要考慮效率問題,很多時候,多線程就會被提上議程,這樣,想不麻煩,都不行鳥。基於Service的傳輸
既然存在外部太慢,那麼還是在記憶體層級解決問題好了,這時候,你可能就需要請出Android四大組件之一的Service了。Service設計的本意,就是提供一些背景服務,資料存取,也可以歸於其職責的一部分。
Service是提供了直連機制,調用的Activity,可以通過
bindService方法,與目標Service建立一條資料通路,拿到
IBinder。這樣,通過Android提供的IPC模型,就可以進行遠程方法的調用和資料的傳輸了。
如上,通過這種模式,可以解決一定問題,但是對於Service來說,實在是太大才小用了,Service的專長,不是在資料,還是在邏輯。對於傳資料而言,Service還是重量了一點,不但是有串連耗精力,傳輸經由IPC,寫起來也夠費勁。而且作為組件,Service隨時可能死掉,你還是要費勁心機的處理資料的持久化,得不償失。
利用Application傳輸
好吧,如果你需要在不同頁面之間共有某個記憶體對象,很合適的一種方式是把它們扔到Application裡面。Application是Context的一個子類,它會在整個應用任何一個組件起來之前,先起來噓噓。它的生命週期會貫穿整個應用所有組件的生命旅途,因此,放在其中的對象,不會被處理掉。
在Activity中,可以通過
getApplication介面,隨時獲得Application對象的引用,用於實現一些全域對象的儲存,和處理,真是最合適不過的地方了。
當然,好東西也不要使用過度,可以想象,由於Application存活周期長,其上引用的對象一直缺少被釋放的機會,如果你把它當成垃圾場,什麼東西都往裡扔,汙染環境,混亂邏輯不提,單就是濫用記憶體資源這一項,就夠罪孽深重一把了。因此,如果資料不是真的需要全域使用,不要擱在其中,如果資料太大,不要全部load出來,合理使用資料庫等外存放裝置,還是必須要的。
結語
還有一些特殊情況,可以考慮用一些特殊的方式。比如子Activity之間,可以通過調用getParent獲得父Activity的引用,來訪問期間的對象,云云。小眾情況,姑且不提。
以上這些概念,我相信所有的coder都了如指掌,如何處理這樣的資料,都心如明鏡。我只是給它們套上了一件Android的外衣,讓初入Android的coder們,能迅速找到心儀的兵器,劈山砍石,攻城拔寨。