Android Dev Summit '21 精彩內容盤點

語言: CN / TW / HK

theme: juejin

每年9/10月份 Google 都會舉行為期約2天的 Android Dev Summit,在活動上 Google 的技術專家們會分享一些 Android 領域的技術動向以及開發心得。

Android Dev Summit 2021: https://developer.android.com/events/dev-summit

今年的活動在線上如期舉行。今年的 Slogan 是 “Excellent apps,across devices” , 即使用 Jetpack 等 MAD Skill (Moden Android Development) 開發出更優秀的應用,並通過 Android 系統落地到更多種類的智慧裝置。本次活動圍繞這一主旨做了 30 多場技術分享(影片),涉及多個方向:

  • Android 12
  • 12L
  • Building across screens
  • Kotlin
  • Jetpack
  • Jetpack Compose
  • Android Studio
  • AGP


Android 12


Material You

Android12 在10月進行了正式推送。Android12 的最大亮點就是基於 Material You 設計語言對原生系統 UI 進行了重新設計。 Material You 是 Material Design 的第3個版本,距離上一代 M2 已經過去了4年

跟上一代 M2 相比 M3 的元素面積更大、更便於使用者點選;同時圓角的角度更大使得並排的元素之間的間隔更清晰。個性化是 M3 最大的特點,這也是 "You" 的命名來源。Android12 遵循了 M3 的 Dynamic Color 設計原則,系統可以從使用者的桌布中抓取顏色,然後色階化應用到你開發的應用中,應用跟隨主題的不同和變換顏色,千人千面。

Stretch OverScroll

https://developer.android.com/training/gestures/scroll#implement-stretch-overscroll

Android12 中加入了 Stretch OverScroll Effect ,相對於以前的水波紋效果,滾動反饋更加真實自然。開發者可以使用新增的 getDistance()onPullDistance() API 來控制 OverScoll 的強度,當然你也可以通過 XML 中設定 android:overScrollMode="never" 來遮蔽此效果。

scroll.gif

App Splash Screen

https://developer.android.com/guide/topics/ui/splash-screen/migrate

Android12 增加了 Splash Screen API,可以在進入 App 主頁之前自動插入開屏頁,當然它的目的是為了讓應用減少白屏的等待時間而非廣告植入。Spash Screen 預設使用 App 的 Icon 作為開屏圖案,開發者也可以使用系統提供的 API 自定義開屏圖案甚至動畫。如果在非 Android12 裝置上也想使用Splash Screen功能,則可以使用 Jetpack 也提供了同名 SplashScreen 庫,適配到了低至 Android 6(APP 23)的裝置。需要注意,如果你的專案中通過 android:windowBackground 或者 CustomActivity 的方式自定義了開屏頁,則需要進行適配,避免在 Android12 中出現兩次開屏

Foreground service restrictions

https://developer.android.com/guide/components/foreground-services#background-start-restrictions

Android8 出於隱私保護的考慮,禁止了 Service 的後臺啟動,本次 Android12 中的限制進一步加強,除了一些特殊情況外,Foreground Service 也不允許在後臺啟動,否則會丟擲 ForegroundServiceStartNotAllowedException 異常。 Service 的存在越來越雞肋,或將逐漸被 WorkManager 所替代

Compatibility Test

每一個新版本的 Android 系統升級都會帶來不少 API 的行為變動,Android12 也不例外。為了確保你的 APP 在這些變動下行為正常,一般需要修改 targetSDKVersion 進行鍼對性的測試。 Android11 起提供了相容性測試工具,在不重新編譯 APK 的情況下可以針對變動的 API 進行測試、提高測試效率。

Developer options > App compatibility changes 中可以找到測試工具


12L (Android 12 Large Screens)


https://developer.android.com/about/versions/12/12L

近年來,搭載 Android 系統的大屏裝置增長迅速,除了平板類產品以外又出現了摺疊屏手機這一新興門類,目前已經有超過250萬部大螢幕裝置上執行著 Android 系統。為提高大屏裝置的使用體驗。 Android12 即將推出一個專門為大屏優化的版本,命名 12L。12L 針對大屏裝置和摺疊屏對介面進行了優化,例如當螢幕寬度大於 600dp 時將預設顯示兩列內容、引入了類似 Chrome OS 的 Dock 欄等,同時支援拖拽分屏等功能,同時在不同視窗中啟動多個應用

WindowManager

https://medium.com/androiddevelopers/using-workmanager-on-android-12-f7d483ca0ecb

為應對更多種類螢幕的出現,Jetpack 提供了 WindowManager 庫,便於 App 更好地適配不同螢幕的尺寸。多視窗模式下的 App 不能再依賴 Display.getRealMetrics() 獲取視窗尺寸,當螢幕狀態變化導致,OnConfigurationChanged 發生時,使用 WindowManager 的 WindoeMetrics 獲取準確的視窗尺寸,再根據 WindowSizeClass 以最合適的佈局顯示當前 UI。

Jetpack Compose 能更好地以響應式的方式處理 OnConfigurationChanged 時的 UI 變化,非常適合配合在 12L 的裝置上使用。

```kotlin enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

@Composable fun Activity.rememberWindowSizeClass() { val configuration = LocalConfiguration.current val windowMetrics = remember(configuration) { WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(this) } val windowDpSize = with(LocalDensity.current) { windowMetrics.bounds.toComposeRect().size.toDpSize() } val widthWindowSizeClass = when { windowDpSize.width < 600.dp -> WindowSizeClass.COMPACT windowDpSize.width < 840.dp -> WindowSizeClass.MEDIUM else -> WindowSizeClass.EXPANDED }

val heightWindowSizeClass = when {
    windowDpSize.height < 480.dp -> WindowSizeClass.COMPACT
    windowDpSize.height < 900.dp -> WindowSizeClass.MEDIUM
    else -> WindowSizeClass.EXPANDED
}

// Use widthWindowSizeClass and heightWindowSizeClass

} ``` 本次活動中分享的不少新技術都第一時間是賠了 Compose ,這也反映出 Android 將 Compose 作為首選的 UI 解決方案的決心。

Activity embedding

除了可以多視窗中開啟多個應用,12L 還可以藉助 XML 的配置或者呼叫 WindowManager 提供的 API 實現同一應用下多個 Activity 的並排顯示。

activity_embdding.gif


Building across screens


Android Ware

Compose 技術棧採用了分層設計的思想,只要替換區域性元件就可以遷移到不同平臺中使用,例如 WareOs 中只需要替換 Material 和 Navigation 的便可以實現穿戴裝置 UI 的開發。

以一個卡片為例,除了新增個別 Composable 以外,與手機端的寫法別無二致

kotlin AppCard( appImage = { Image(painter = painterResource(id = R.drawable.ic_message), ... ) }, appName = { Text("Messages") }, time = { Text("12m") }, title = { Text("Kim Green") }, onClick = { ... }, content = { Column(modifier = Modifier.fillMaxWidth()) { Text("On my way!") } }, )

Android for Cars

Android 提供了兩套車機系統 Android Auto 以及 Android Automotive OS。

  • Android Auto 提供了針對駕駛員優化的應用體驗,使用者在 Android Auto 上建立連線手機的服務,手機應用可以以更優化的介面顯示在車機上。
  • Android Automotive OS 是一款基於 Android 的車載資訊娛樂系統。車載系統是專為提升駕駛體驗而優化的獨立 Android 裝置。相對於 Android Auto,它無需藉助手機,使用者可以將應用直接安裝到車載系統上。

開發者可以跨平臺的工程結構開發車機應用:

  • car_app_common 是共享部分
  • automotive_osandorid_auto 是兩個 build target


Kotlin


Kotlin Flow

https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb

Kotlin方面,本次活動上重點推薦了 Kotlin Flow 在 MVVM 架構中的應用。基於 Jetpack 的 lifecycle-ktx 擴充套件庫 Flow 可以轉變為一個 lifeycle-aware 元件,較好地替代現有的 LiveData 的使用場景。

你可以只在 Model 層使用 Flow,在 View 層仍然使用 LiveData,通過 Flow.asLiveData 將 Flow 轉換為 LiveData:

kotlin // import androidx.lifecycle.asLiveData class MessagesViewModel(repository: MessageRepository) : ViewModel() { val userMessage = repository.userMessage.asLiveData() ... }

當然 View 層也可以直接使用 Flow,在 lifecycleScope.launch { }lifecycleScope.launchWheStart { } 中收集 Flow 的資料避免洩露,但是從效能出發更推薦使用 repeatOnLifecycle: ```kotlin //imprort androidx.lifecycle.repeatOnLifecycle

class MessagesActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.userMessages.collect { messages -> listAdapter.submitList(messages) } } } } } ``` 當 MessagesActivity 離開 STARTED 時,協程及時取消節省資源。

此外使用 stateIn 可以將 Flow 轉化為一個 StateFlow 以熱流的形式確保資料的下游共享。 活動期間有網友在直播中詢問是否還有 Flow 無法取代 LiveData 的場景,官方的回答是 LiveData 除了 API 更簡單以外(相應的功能也比較弱),已經完全可以被 Flow 替代。

KSP

https://android-developers.googleblog.com/2021/09/accelerated-kotlin-build-times-with.html

KSP (Kotlin Symbol Processing) 於9月份釋出了 1.0 正式版。相比較於 KAPT 需要生成 Java Stub 後再基於 APT 處理註解的流程,KSP 底層基於基於 Kotlin Compiler Plugin ,省去了 Java Stub 的生成,編譯速度可以提高2倍以上,未來在 Kotlin Multiplatform Project 中也可使用,如果你的專案程式碼已經遷移到 Kotlin,那麼未來的註解處理應該首選 KSP。

```kotlin apply plugin: 'com.google.devtools.ksp'

dependencies { ... implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" ksp "androidx.room:room-compiler:$room_version" } ```

將 KAPT 替換為 KSP 的配置非常簡單,目前已經有包括 Room 在內的許多常見框架對 KSP 進行了支援,未來 Dagger,Hilt 等也將接入 KSP 以加速註解處理。


Jetpack


Room

https://medium.com/androiddevelopers/room-auto-migrations-d5370b0ca6eb

10月份 Room 釋出 2.4.0 Beta 01,主要新增了 Auto MigratioinsMulti-map Relations 兩個新 Features,同時支援使用 KSP 進行註解處理。

當資料庫表結構發生變化時,需要通過資料庫遷移保證資料的不丟失,例如欄位名變化之類的變更,需要手寫 SQL 才能完成升級,而基於 Auto Migrations 可以檢測出兩個表結構的區別,完成自動升級。 kotlin @Database( version = MusicDatabase.LATEST_VERSION, entities = { Song.class, Artist.class }, autoMigrations = { @AutoMigration ( from = 1, to = 2 ) }, exportSchema = true ) public abstract class MusicDatabase extends RoomDatabase { ... }

之前的版本中 Room 使用 @Relatioin 進行外來鍵關聯,為了避免多寫 SQL 需要單獨額外定義 Relatioin Class,其實對於 SQL 的態度沒必要談虎色變,適當地活用 SQL 有助於更簡單地定義一對多的實體關係。

```kotlin //Room Relations

data class ArtistAndSongs( ` @Embedded val artist: Artist, @Relation(...) val songs: List )

@Query("SELECT * FROM Artist") fun getArtistAndSongs(): List

//Room Multimap

@Query("SELECT * FROM Artist JOIN Song ON Artist.artistName = Song.songArtistName") fun getAllArtistAndTheirSongsList(): Map> ```

Map<Artist, List<Song>> 這樣的資料結構使用起來也更簡單

WorkManager

https://medium.com/androiddevelopers/using-workmanager-on-android-12-f7d483ca0ecb

WorkManager 已經不單單是一個簡單的非同步任務處理框架,更是一整套強大的任務排程方案,可以有效替代 Service,更可靠地執行長時間的任務。最低可以向後相容到 6.0,覆蓋了市場絕多大數的機型。

WorkManager 2.6 支援 Multi-Process,藉助 RemoteListenableWorker 或者 RemoteCoroutineWorker 可以將任務執行在任意指定程序,實現跨程序的監聽;為應對 Android12 的 Foreground Service 的啟動限制,WorkManager 2.7 新增了 setExpedited API,可以高優的立即啟動相關任務,不受後臺啟動的約束。

kotlin val request = OneTimeWorkRequestBuilder<HighPriorityWorker>() .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build() WorkManager.getInstance(context).enqueue(request)

由於 CoroutineWorker.setForeground()ListenableWorker.setForegroundAsync() 方法由 Foreground Service 提供支援,在一些禁止後臺啟動的場景中一旦被呼叫,會發生 ForegroundServiceStartNotAllowedException 異常,這是在開發中需要特別注意的。

More Components

此外,Jetpack 的其他一些庫近期也都有新版本的釋出。Navigation 2.4.0 beta 增加了多棧返回的支援,不同 NavHostFragment 的返回棧可以各自管理;DataStore 釋出 1.0 可以更安全地替代 SharedPreferences 的使用;CameraX 1.1.0-alpha10 增加了 VideoCapture 影片截圖和曝光補償等實用功能; Benchmark 1.1.0-alpha11 增加了 Frame Timing,效能測試更加精準,並向後相容到 API 23。


Jetpack Compose


Compose 新增 androidx.compose.material3 庫,支援開發 Material You 主題風格的 UI。

Material3

Compose.M3 通過 ColorScheme 來自定義配色方案,支援了 Material You 的 color scheme 設計規範。 ```kotlin private val Blue40 = Color(0xff1e40ff) private val DarkBlue40 = Color(0xff3e41f4) private val Yellow40 = Color(0xff7d5700)

// Remaining colors from tonal palettes private val LightColorScheme = lightColorScheme( primary = Blue40,
secondary = DarkBlue40,
tertiary = Yellow40,
// error, primaryContainer, onSecondary, etc. )

private val DarkColorScheme = darkColorScheme( primary = Blue80,
secondary = DarkBlue80,
tertiary = Yellow80,
// error, primaryContainer, onSecondary, etc. ) ```

如上,定義 light 和 dark 兩種 scheme,然後引數傳遞給 MaterialTheme

```kotlin val darkTheme = isSystemInDarkTheme()

MaterialTheme( colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme ) { // M3 app content } ```

Dynamic Color

Dynamic color 是 Material You 的最主要特色,在 Android12 及其後續裝置可以通過設定 Dynamic ColoScheme 實現動態顏色切換:

```kotlin // Dynamic color is available on Android 12+

val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S val colorScheme = when { dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current) dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
darkTheme -> DarkColorScheme
else -> LightColorScheme } ```

如上,當應用了 Dynamic ColorScheme 後,選擇紅色或者藍色牆紙後 App 的 UI 呈現對應的主題顏色


Android Studio


  • Android Studio Arctic Fox 正式版釋出
  • Ancroid Studio Bumblebe 進入 Beta 階段
  • 而最新的 Canary 版本是 Chipmunk。

這近幾個版本的迭代中 Android Studio 面向如何提高開發者的編碼和除錯效率增加了一系列新功能。

Compose @review

最近的 Andorid Studio 版本中對 Compose 的預覽功能進行了多項強化:像原生檢視那樣,支援對 Compose UI 進行 3D 佈局預覽;對於一些字面值變數的修改無需重新編譯即可實現預覽的實時更新:

live-editing-of-literals (1).gif

新增 Preview Configuration 面板,對 @Preview 註解中的引數修改更加快捷;

Jank Detection

在 Performance Profile 中新增了 Frames 檢視,可以監控每一幀的耗時情況,更好地除錯和發現 Jank 一類的問題。

此外,Android Studio 對模擬器進行了不少強化,模擬器模擬更多真實裝置的使用場景,例如重力感應等。


AGP(Android Gradle Plugin)


Non-transitive R class

AGP 7.0 以來針對編譯速度的提升下了不少功夫,例如對 KSP 以及 Non-transitive R class 的支援。 Non-transitive R class 通過顯示指定資原始檔的完整包名,避免了 R 檔案的隱式傳遞依賴、提升了編譯速度,AGP 配合新的 Androi Studio 可以對工程進行 Non-transitive R class 的一鍵重構

Incremental Lint

AGP 7.0 引入 Lint 增量檢查,大幅提升了 Lint 的檢查速度

Configuration cache

https://medium.com/androiddevelopers/configuration-caching-deep-dive-bcb304698070

AGP 通過 Gradle 配置快取的開啟,可以顯著提升各種情況下的編譯速度

在 Android Studio 的 gradle.properties 中增加一下配置即可啟動 Configuration Cache

org.gradle.unsafe.configuration-cache=true


Summary


Android Dev Summit 的分享主題涉及了 Android 領域的方方面面,開發者無需瞭解,更重要的是從這些分享中洞察到未來的技術的發展趨勢,比如未來的 App 可能需要適配更多而螢幕尺寸、Jetpack Compose 在 UI 開發上的先進性正逐漸凸顯;Kotlin Flow 對 LiveData 以及 WorkManager 對 Service 的替代趨勢也逐漸清晰。。