Android Weekly Issue #463
Room auto-migrations
Room 2.4.0-alpha01推出了Auto migration, 讓數(shù)據(jù)庫遷移更加容易.
@Database(
version = 2,
entities = [ GoodDoggos.class ],
autoMigrations = [
AutoMigration (
from = 1,
to = 2,
spec = DoggosDatabase.DoggosAutoMigration::class
)
]
)
abstract class DoggosDatabase : RoomDatabase {
@RenameTable(fromTableName = "Doggos", toTableName = "GoodDoggos")
class DoggosAutoMigration: AutoMigrationSpec { }
}
自動遷移可以和手動遷移結合, 滿足開發(fā)者的需求.
對于自動遷移還有測試的支持.
A Compose & Viewmodel integration test with Hilt
一個簡單的小例子, UI是用Compose, 注入用Hilt.
ViewModel中的state類型:
sealed class UiState {
object Loading : UiState()
object Empty : UiState()
data class Content(val items: List<Item> = listOf()) : UiState()
}
Repository返回flow, flow轉(zhuǎn)UiState的方法:
private suspend fun Flow<List<Item>>.toUiState(): Flow<UiState> = map {
if (it.isEmpty()) {
UiState.Empty
} else {
UiState.Content(items = it)
}
}.onStart {
emit(UiState.Loading)
}
測試的時候, 需要假數(shù)據(jù), 所以替換掉了Repository:
@TestInstallIn(components = [SingletonComponent::class],
replaces = [InventoryRepositoryModule::class])
@Module
object FakeInventoryRepositoryModule {
@Singleton
@Provides
fun provideFakeInventoryRepository() = object : InventoryRepository {
@ExperimentalCoroutinesApi
override suspend fun items(): Flow<List<Item>> {
return flowOf(dummyItems)
}
}
}
需要test runner:
class HiltTestRunner : AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?,
): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
最后測試寫成這樣:
@ExperimentalCoroutinesApi
@HiltAndroidTest
class ItemListTest {
@get:Rule(order = 1)
var hiltTestRule = HiltAndroidRule(this)
@get:Rule(order = 2)
var composeTestRule = createAndroidComposeRule<MainActivity>()
@Before
fun setup() {
hiltTestRule.inject()
composeTestRule.setContent {
TallyApp(composeTestRule.activity.viewModels<ListViewModel>().value)
}
}
@Test
fun app_displays_list_of_items() {
//assert the list is displayed
composeTestRule.onNodeWithTag(InventoryListTag).assertIsDisplayed()
//assert all items exist within the tree
dummyItems.forEach { item ->
composeTestRule.onNodeWithText(item.name).assertExists()
}
}
}
Tap Response Time: Jetpack Navigation
關于點擊響應時間的進一步探索.
Navigation Drawer using Jetpack Compose
Navigation Drawer的Compose實現(xiàn).
代碼見:
https://github.com/walnashgit/ComposeNavigationDrawer/tree/feature/ComposeNavDrawerUsingModalDrawer
Unit testing on Android
單元測試:
- ViewModel
- 自定義View
- 擴展方法
測試LiveData還有一個工具類.
Lessons learned when migrating my app to Jetpack Compose
一些經(jīng)驗和資源介紹.
Getting ready for Declarative UIs — Part 3 — Why Declarative UIs on Android?
為什么要用聲明式UI.
- 首先講了有限狀態(tài)機.
- Interoperability的實例.
- 保存變量除了有
remember
之外還有Composition Local. - 關于SideEffect推薦閱讀這篇文章.
- 關于單向數(shù)據(jù)流, 看這篇文章.
- Screenshot testing: https://blog.karumi.com/jetpack-compose-screenshot-testing-with-shot/
CoroutineScope and coroutineContexts
關于測試中CoroutineContext的探討.
always keep currentCoroutineContext() and coroutineContext pointing to the same value.
Pi Practice App in Compose
一個小應用, 之前使用Anko做的, 現(xiàn)在改用Compose做了.
Code
- https://github.com/skydoves/Lazybones 流式的生命周期訂閱相關
- https://github.com/igorescodro/alkaa 一個todo app.