Android Weekly Issue #466
Static analysis tools for Android
Android的靜態(tài)分析工具.
- Android lint
- ktlint
- detekt
各自舉了一個(gè)例子來(lái)說(shuō)如何自定義規(guī)則.
Navigation: Nested graphs and include tag
Navigation graph支持嵌套.
<navigation>
標(biāo)簽.
可以放在一個(gè)新的文件中, 再include進(jìn)來(lái).
這樣就可以跨module組織代碼了.
Avoid CI/CD Lock-in — Make Your Builds More Portable
讓CI更具可移植性.
- 把腳本放在代碼庫(kù)里.
- 把gradle任務(wù)放在shell腳本里.
- 盡量使用gradle插件而不是ci插件.
- 使用容器化技術(shù).
- 最小化在ci上的配置.
Assisted Injection With Dagger and Hilt
對(duì)于構(gòu)造一個(gè)對(duì)象, 有些參數(shù)需要DI容器幫忙, 有些參數(shù)你想自己提供的情況.
- 解決方案1: 添加AutoFactory依賴, 和daggeer結(jié)合使用, 會(huì)生成一個(gè)工廠.
- 解決方案2: dagger2.31+之后, 使用
@AssistedInject
注解, 標(biāo)記在構(gòu)造函數(shù)上, 想要手動(dòng)提供的參數(shù), 標(biāo)記@Assisted
. 使用@AssistedFactory
創(chuàng)建一個(gè)工廠.
對(duì)ViewModel來(lái)說(shuō), 還需要提供一個(gè)ViewModelProvider.Factory
的實(shí)現(xiàn).
Dagger 2 and Jetpack Compose Integration
Dagger2和Jetpack Compose的集成.
首先, 開(kāi)篇定義navigation, 假定每個(gè)屏幕需要一個(gè)ViewModel:
setContent {
val navController = rememberNavController()
NavHost(navController, startDestination = NavigationDestination.Screen1.destination) {
composable(NavigationDestination.Screen1.destination) {
val viewModel: Screen1ViewModel = viewModel()
Screen1(viewModel = viewModel)
}
composable(NavigationDestination.Screen2.destination) {
val viewModel: Screen2ViewModel = viewModel()
Screen2(viewModel = viewModel)
}
}
}
后來(lái), 換成這種:
composable(NavigationDestination.Screen1.destination) {
val viewModel: Screen1ViewModel = hiltNavGraphViewModel()
Screen1(viewModel = viewModel)
}
hiltNavGraphViewModel()
做了什么呢?
- 找ViewModel的owner: Hilt用了
LocalViewModelStoreOwner
, 可以是Activity, Fragment, 在composable中, 是NavBackStackEntry
.
了解Hilt怎么做之后, 看看Dagger 2.
setContent {
val navController = rememberNavController()
NavHost(navController, startDestination = NavigationDestination.Screen1.destination) {
composable(NavigationDestination.Screen1.destination) {
// option #1 create a component inside NavBackStackEntry,
// which can be helpful if we need to provide more than one object from DI here
val component = DaggerScreen1Component.builder().build()
val viewModel: Screen1ViewModel = daggerViewModel {
component.getViewModel()
}
Screen1(viewModel = viewModel)
}
composable(NavigationDestination.Screen2.destination) {
val viewModel: Screen2ViewModel = daggerViewModel {
// option #2 create DI component and instantly get ViewModel instance
DaggerScreen2Component.builder().build().getViewModel()
}
Screen2(viewModel = viewModel)
}
}
}
Infinite auto-scrolling lists with RecyclerView & LazyLists in Compose
無(wú)限自動(dòng)滾動(dòng)的list, 有點(diǎn)像走馬燈的效果.
Kotlin SharedFlow or: How I learned to stop using RxJava and love the Flow
- RxJava后臺(tái)任務(wù)分步驟進(jìn)行UI顯示 -> Flow.
- 處理熱流:
- PublishSubject -> SharedFlow.
- BehaviorSubject -> StateFlow.
一些特點(diǎn):
-
StateFlow
是conflated: 如果新的值和舊的值一樣, 不會(huì)傳播. -
SharedFlow
需要合理設(shè)置buffer和replay策略. -
StateFlow
和SharedFlow
永遠(yuǎn)都不會(huì)停止. 不能指望它們的onCompletionCallback
.
還有文中提到了一個(gè)觀點(diǎn), 為什么不繼續(xù)用LiveData呢? 因?yàn)長(zhǎng)iveData感覺(jué)是跟Android相關(guān)的一個(gè)類, 而SharedFlow和StateFlow是Kotlin的, 這樣感覺(jué)domain層脫離了對(duì)Android的依賴, 更解耦一些.
From Junior to Master in Kotlin — 1 (Basic Syntax)
一些Kotlin的用法.
Code
News
- #AndroidDevChallenge - It’s a wrap! Jetpack Compose Challenge的總結(jié), 可以訪問(wèn)獲勝者的代碼庫(kù).