安卓開發大神級人物 JakeWharton 前不久在接受採訪時提出一個頗具爭議而又沒有給出原因的建議:一個 App 只需要一個 Activity ,你可以使用 Fragments,只是別用 Fragments 回退棧。
針對這一言論,有關 JakeWharton 建議的背後原因的一個提問迅速在 Reddit 國外網站的安卓開發頻道引發熱評。
眾多安卓開發人員紛紛提出自己的見解。其中獲贊最高的一條,甚至得到 JakeWharton 本人的親自贊評。
我們來看看這條回答都提到了哪些內容,對 Activity 和 Fragment 之間的愛恨情仇有何獨到的見解,憑什麼能得到 JakeWharton 本尊的青睞有加。
因為 Activity 是一個程式入口。你可以將其視為 app 的一個 main
函式。站在使用者的立場上,通常你進入 app 的方式可能包括以下幾種:
-
launcher 桌面程式(
main
函式入口); -
來自引數化
main
函式入口的通知欄,並且導航到 app 的指定位置; -
如果你做的是一個相機應用,那麼需要處理圖片請求的 intents;
-
如果你做的是一個社交產品,那麼需要處理
share
請求的 intents;
差不多類似這些場景。
但是,如果你真的不用分享和來自應用的 intents 的話,並且唯一的程式入口就是 launcher 桌面,別為每一個頁面建立一個新的入口。這樣做其實沒有意義。為什麼沒有意義?因為這種場景下,程式死掉後 launcher 能夠啟動任何你應用中的 Activity 頁面。
Fragments 是處理生命週期事件的檢視控制器,並且非常不錯。然而,Fragments 回退棧簡直垃圾;回退棧變化監聽器總是不正常地被呼叫( 1 次 transaction 三次呼叫?),並且不告訴你呼叫什麼,而在恢復事務時也不知道哪些 fragments 是可用的。
你可以給事務新增 tag 標籤,然後從棧中彈出操作,但是僅僅是一個 main -> Events -> Details(id=123)
的操作流程就相當繁瑣了。
同樣的,一旦你將一個 Fragment 放進回退棧中,我個人不知道它的生命週期開始做什麼。我曾經遇到過一個後臺中的 fragment 被呼叫四次 onCreateView()
方法,我甚至不知道究竟怎麼了。而沒有位於回退棧中的 Fragments 是可以被預見的。它們的動畫支援有點古怪,但至少它們還能使用。
所以如果你想知道哪些 Fragments 是你能夠操作的並且哪些 views 是你正在展示的並且能夠在你自己的導航狀態控制之中,那麼你應該自己處理導航操作。把“應用邏輯”抽象化到一個 presenter(亦楓注:MVP 模式)中聽起來來很棒,但是你是不是脫離了應用檢視層裡面的真實情況?
但是單一 activity 的優勢是什麼?
更簡單的生命週期處理(例如,當 app 進入後臺時,你只需要處理 onStop
方法),更少錯誤空間,和更多控制。同樣的,你可以移動檢視層外面的導航狀態到 domain 層,或者至少到 presenter 中。不需要太多 view.navigateToDetail(songId)
之類的東西,你只需要在你的 presenter 或者 ViewModel 或者無論哪些時髦的用法中使用 backstack.goTo(SongKey.create(songId))
就行。藉助一個合適的庫,當你到了 onResume
時它會自動將這些導航呼叫加入佇列,並且不會致使 fragment 事務發生崩潰,非常得好。
儘管 Google 給出的案例也在用 commitAllowingStateLoss()
,我有使用 commitNow()
的動畫愛好。在我看來,單個 activity 能夠看得見的好處就是,頁面間共享 views 的能力,取代通過使用 <include
標籤在 18 個佈局檔案重複檢視。其他當然是更簡單的導航操作。
以上便是深得 JakeWharton 大神心意的一條回答。話雖如此,但是系統 Fragment 存在的未解之謎或者說出乎你意料的坑實在太多。如果一定要在多 activity 部分 fragments 和單 activity 多 fragments 之間選擇的話,我想不只是我,很多人還是毫不猶豫地選擇前者。
更多討論內容,參見:
備註:關於使用 Fragments 的那些道道,我之前也寫過相關總結性的文章來,感興趣地不妨去我的部落格搜尋看看。
關於我:亦楓,部落格地址:yifeng.studio/,新浪微博:IT亦楓
微信掃描二維碼,歡迎關注我的個人公眾號:安卓筆記俠
不僅分享我的原創技術文章,還有程式設計師的職場遐想
彩蛋:公眾號回覆關鍵字“面試資料”,獲取 BAT 面試大牛為你準備的全套面試資料!