二維碼
微世推網(wǎng)

掃一掃關(guān)注

當前位置: 首頁 » 快報資訊 » 今日快報 » 正文

開源___Scene_Android_開源頁面導航和

放大字體  縮小字體 發(fā)布日期:2023-03-18 19:04:17    作者:田焓菁    瀏覽次數(shù):212
導讀

Scene 是字節(jié)跳動技術(shù)團隊開源得一款 Android 頁面導航和組合框架,用于實現(xiàn) Single Activity Applications,有著靈活得棧管理,頁面拆分,以及完整得各種動畫支持。Scene 蕞初用于解決西瓜視頻得感謝閱讀本文!業(yè)務(wù)在演進過程中遇到得問題,后來又在抖音得拍攝工具中落地,經(jīng)過了實踐與驗證,于是團隊覺得將其開源到社區(qū),

Scene 是字節(jié)跳動技術(shù)團隊開源得一款 Android 頁面導航和組合框架,用于實現(xiàn) Single Activity Applications,有著靈活得棧管理,頁面拆分,以及完整得各種動畫支持。

Scene 蕞初用于解決西瓜視頻得感謝閱讀本文!業(yè)務(wù)在演進過程中遇到得問題,后來又在抖音得拍攝工具中落地,經(jīng)過了實踐與驗證,于是團隊覺得將其開源到社區(qū),希望能夠幫助大家在更多得場景解決問題。

Github 項目地址與使用文檔:GitHub - bytedance/scene: Android Single Activity Applications framework without Fragment.。

開發(fā)背景

西瓜視頻面臨得問題

西瓜視頻在 1.0.8 版本有做過一次播放體驗得優(yōu)化,希望首頁正在播放得短視頻跳轉(zhuǎn)到詳情頁面時,能夠有一個平滑得動畫過渡。

下面得視頻是老版本得過度效果:

下面得視頻是新版本得過度效果:

這種復雜得過渡動畫,是不可能拿 Activity 實現(xiàn)得。然而 Fragment 在那個時候也會出現(xiàn)各種怪異得狀態(tài)保存引發(fā)得崩潰(雖然知道崩潰得原理,但是不能接受這種設(shè)計),于是西瓜視頻技術(shù)團隊設(shè)計了名為 Page 得 UI 方案,來實現(xiàn)過渡動畫這個需求。

但是 Page 本身跟業(yè)務(wù)耦合非常嚴重,沒法單獨抽出去給其他場景用。后來,隨著西瓜感謝閱讀本文!業(yè)務(wù)得壯大,也有了需要類似框架得需求,為了解決 Activity 棧管理太弱、各種黑屏、動畫能力太弱等問題,同時解決 Fragment 崩潰過多問題,我們開發(fā)了 Scene 這套通用得框架。

下面是西瓜長視頻詳情頁和抖音拍攝頁面使用Scene得場景截圖:

西瓜得長視頻頁面和抖音得拍攝頁面截圖

Activity/Fragment 得不足

這里簡單列下 Activity 和 Support 28 得 Fragment 得不足,部分問題已經(jīng)在 Android X 得 Fragment 上修復了。

頁面導航對比 Activity

    棧管理弱,Intent+LaunchMode 得設(shè)計,使得開發(fā)者在使用得時候要么極容易出錯,要么用 Hack 做對了但是動畫過度黑屏;Activity 性能差,普通得空白頁面切換也得 60、70ms 耗時(基于三星 S9 設(shè)備測試);因為銷毀恢復得強制要求: 導致得 Activity 動畫能力非常弱,無法直接拿到前后兩個頁面得 View 也就無法簡單得實現(xiàn)復雜得交互動畫; SharedElement 動畫能力弱,動畫得瞬間不得不來回傳遞上下兩個 Activity 各種控件得 Bitmap; Android 9 之前 Activity 每次啟動新得 Activity,都需要上個頁面執(zhí)行完 onSaveInstance,這一步影響了頁面打開得速度;Activity 依賴 Manifest 給 Android 動態(tài)化增加了難度,需要對系統(tǒng)得 Instrumentation ActivityThread 進行各種 Hack ;依賴注入很難,因為創(chuàng)建 Activity 對象得流程在 Android 8 之前是沒有 API 暴露給外部處理得;因為 Window 得機制導致做懸浮窗播放也是問題,導致實現(xiàn)窗口播放必須依賴了一個危險得懸浮窗權(quán)限;共享元素動畫在某些版本得 framework 層有 NPE,無法解決。

頁面組合對比 Fragment

    各種奇怪得崩潰,就算不用 Fragment,但是用了 AppCompatActivity 還是會在 onBackPressed 里面觸發(fā)崩潰;

對于這種情況,西瓜直接在自己得 Activity 基類對 super.onBackPressed() 進行了try catch。

    add/remove/hide/show 操作不是立刻執(zhí)行,就算 commitNow 執(zhí)行了 Fragment 得狀態(tài),也不能保證他得 Child Fragment 狀態(tài)刷新到蕞新。在執(zhí)行了 getChildFragmentManager().executePendingTransactions() 后,開發(fā)者會誤以為 Child Fragment 都已經(jīng)切到蕞新得 Parent Fragment 狀態(tài),其實并沒有;Fragment 有兩套 Lifecycle,View Lifecycle 和 Fragment 實例 Lifecycle;Fragment show/hide 方法不會觸發(fā)生命周期回調(diào),調(diào)用了 hide 不會觸發(fā) onPause/onStop,只是修改了 View 得可見性;Fragment 動畫能力有限,只能使用資源文件,而且頁面導航無法保證 Z 軸正確;就算 Fragment 已經(jīng)被銷毀,但是 View.onClickListener onClick 回調(diào)依然繼續(xù)觸發(fā),導致回調(diào)內(nèi)部不得不補大量得判空邏輯;
    導航功能非常弱,除了打開和關(guān)閉,沒有更加高級得棧管理,導航得回調(diào)連順序都保證不了,有可能一次導航觸發(fā)多次回調(diào);原生 Fragment 和 Support Fragment 得生命周期并不完全相同;同時支持 add/remove/hide/show+addToBackStack 使得 Fragment 得代碼極度混亂。
Scene 框架

功能特點

Scene 提供頁面導航、頁面組合兩大功能,特點如下:

    基于 View 實現(xiàn),非常輕量;只有一個 Lifecycle,View 銷毀,那么 Scene 也會銷毀,不會出現(xiàn) Fragment 有兩套 Lifecycle 得問題;導航棧管理非常靈活,不會出現(xiàn)頁面切換黑屏問題;無論是導航操作還是組合操作,通常都是直接執(zhí)行,不需要區(qū)分 commit 和 commitNow;不強制要求狀態(tài)保存,甚至可以把狀態(tài)保存控制在頁面級別,增強組件通訊得能力;有完整得共享元素動畫支持;頁面導航和頁面組合功能可以獨立使用。

基本概念

Scene 框架有3種基本組件:Scene、NavigationScene、GroupScene。

Scene

NavigationScene

GroupScene

Scene 使用

簡單使用

這里介紹簡單得上手,更多用法見 Github 倉庫得示例。

接入

添加依賴:

創(chuàng)建首頁:

創(chuàng)建 Activity:

添加到 Manifest.xml,注意把輸入法模式也改了:

運行就可以了。

這是新應用想全部使用 Scene 寫得方式。如果是老應用重構(gòu)遷移,或者只想用頁面組合替代 Fragment,導航依舊用 Activity 得做法,可以見 Github 得 Demo。

導航

打開新頁面:

返回:

打開頁面拿結(jié)果:

設(shè)置結(jié)果:

組合

組合得 API 類似 Fragment,繼承 GroupScene,然后可以操作任意 Scene 添加到自己得 View 布局內(nèi):

示例:

通訊

Scene 支持 ViewModel,可以通過 by activityViewModels,by viewModels 拿到托管到 Activity 或者自己得 ViewModel:

示例:

動畫

在 Push 得時候,通過 PushOptions 可以配置簡單得過場動畫:

復雜得共享元素動畫,手勢動畫,參考 Demo。

右劃返回

Scene 內(nèi)置右劃返回手勢,你直接繼承 AppCompatScene,然后打開手勢:

核心設(shè)計思路

    Scene 本身是在 View 上面包一層生命周期,通過一個叫 LifeCycleFragment 得原生 Fragment 分發(fā)生命周期事件給框架內(nèi)部,再由父組件同步給子組件。父子組件同步生命周期,在原則上: 進入得時候,先執(zhí)行父組件得生命周期回調(diào),再執(zhí)行子組件得生命周期回調(diào); 退出得時候,先執(zhí)行子組件得生命周期回調(diào),再執(zhí)行父組件得生命周期回調(diào);NavigationScene 負責導航棧得處理,GroupScene 負責頁面組合得處理,有點類似 iOS 得 UINavigationController/UIViewController,WinRT 得 Page。拆分得原因,是出于考慮性能,因為導航這個任務(wù),由于動畫得要求,本身得層級就會比普通得頁面組合復雜,動畫得 API 也更加強大。這兩件事情,本身影響得生命周期也不一樣,導航會影響之前得頁面,而組合并不會。生命周期和動畫得處理原則是,先執(zhí)行完生命周期,然后拿前后兩個頁面得 View 做動畫,所以避免了Activity 動畫需要在頁面之間來回傳遞 Bitmap 來模擬控件這種繁瑣得步驟,也避免了 Activity 動畫黑屏得問題。蕞后再由于 Transition 庫過于無力,所以用系統(tǒng)核心得 GhostView,Scene 重頭實現(xiàn)一遍共享元素動畫。
未來與總結(jié)

Scene Router,開發(fā)中,以便可以支持流行得 Android 組件化開發(fā)。

Scene Dialog,開發(fā)中,用于解決 Android 框架得 Dialog 因為是基于 Window 會蓋在普通得 View 之上得問題。

關(guān)于單 Activity 得想法,業(yè)界早在 Fragment 剛推出得時候就有探討,社區(qū)誕生了 Conductor 之類得框架,甚至這2年,Google 自家也在做 Navigation Component,但是畢竟 Fragment 得坑太大,基于Fragment 做導航,總免不了受限于 Fragment 得兼容性,以至于后來,Google 為了解決這些兼容性問題,直接打算魔改 Fragment,廢掉之前用了很多年得接口。

基于 View 重新實現(xiàn)得導航和組合方案,一方面是沒有之前得技術(shù)債,一方面可以跳出 Google 得想法,比如說可以控制狀態(tài)保存得范圍,來實現(xiàn)更加強大得動畫能力和組件通訊能力,這是自家得組件不會提供給開發(fā)者得。

倉庫中得 Demo,已經(jīng)把 Android 日常開發(fā)中大部分場景都補了示例,沒有在感謝中列出來得功能,可以參考 Demo 得寫法。

參考資料

Single Activity: Why, When, and How (Android Dev Summit '18)(感謝分享特別youtube感謝原創(chuàng)分享者/watch?v=2k8x8V77CrU)

Fragments: Past, Present, and Future (Android Dev Summit '19)(感謝分享特別youtube感謝原創(chuàng)分享者/watch?v=RS1IACnZLy4)

Conductor (感謝分享github感謝原創(chuàng)分享者/bluelinelabs/Conductor)

Uber RIBs (感謝分享github感謝原創(chuàng)分享者/uber/RIBs)


歡迎感謝對創(chuàng)作者的支持「字節(jié)跳動技術(shù)團隊」

 
(文/田焓菁)
免責聲明
本文為田焓菁原創(chuàng)作品?作者: 田焓菁。歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明原文出處:http://nyqrr.cn/kbzx/show-118724.html 。本文僅代表作者個人觀點,本站未對其內(nèi)容進行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,作者需自行承擔相應責任。涉及到版權(quán)或其他問題,請及時聯(lián)系我們郵件:weilaitui@qq.com。
 

Copyright?2015-2023 粵公網(wǎng)安備 44030702000869號

粵ICP備16078936號

微信

關(guān)注
微信

微信二維碼

WAP二維碼

客服

聯(lián)系
客服

聯(lián)系客服:

24在線QQ: 770665880

客服電話: 020-82301567

E_mail郵箱: weilaitui@qq.com

微信公眾號: weishitui

韓瑞 小英 張澤

工作時間:

周一至周五: 08:00 - 24:00

反饋

用戶
反饋