Android Weekly Issue #463
Room auto-migrations
Room 2.4.0-alpha01推出了Auto migration, 让数据库迁移更加容易.
@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 { }
}
自动迁移可以和手动迁移结合, 满足开发者的需求.
对于自动迁移还有测试的支持.
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转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)
}
测试的时候, 需要假数据, 所以替换掉了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实现.
代码见:
https://github.com/walnashgit/ComposeNavigationDrawer/tree/feature/ComposeNavDrawerUsingModalDrawer
Unit testing on Android
单元测试:
- ViewModel
- 自定义View
- 扩展方法
测试LiveData还有一个工具类.
Lessons learned when migrating my app to Jetpack Compose
一些经验和资源介绍.
Getting ready for Declarative UIs — Part 3 — Why Declarative UIs on Android?
为什么要用声明式UI.
- 首先讲了有限状态机.
- Interoperability的实例.
- 保存变量除了有
remember
之外还有Composition Local. - 关于SideEffect推荐阅读这篇文章.
- 关于单向数据流, 看这篇文章.
- 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做的, 现在改用Compose做了.
Code
- https://github.com/skydoves/Lazybones 流式的生命周期订阅相关
- https://github.com/igorescodro/alkaa 一个todo app.
网友评论