Android 开源项目全面解析
架构与框架篇
MVIKotlin 这个项目最近这几年真的火得不行,它把 MVI 架构思想完美地用 Kotlin 实现出来了。MVI 全称是 Model-View-Intent,简单说就是让数据的流向变得超级清晰——用户的每一个操作都是 Intent,状态通过 Model 来管理,View 只负责展示。
让我给你看一段代码你就明白了:
// 定义状态
data class TodoState(
val todos: List<Todo> = emptyList(),
val isLoading: Boolean = false,
val error: String? = null
)
// 定义 Intent(用户行为)
sealed class TodoIntent {
data class LoadTodos(val userId: String) : TodoIntent()
data class AddTodo(val text: String) : TodoIntent()
data class RemoveTodo(val id: String) : TodoIntent()
}
// 实现 ViewModel
class TodoViewModel(
private val repository: TodoRepository
) : ViewModel() {
private val _intentFlow = Channel<TodoIntent>()
val intentFlow: Flow<TodoIntent> = _intentFlow
fun intent(intent: TodoIntent) {
viewModelScope.launch {
_intentFlow.send(intent)
}
}
}
Circuit 是 Square 公司开源的组合式 UI 框架,它和 Jetpack Compose 配合得特别默契。Circuit 的核心思想是用一个 Screen 的概念来管理所有的 UI 状态,这样你就不需要在 ViewModel 里塞一堆状态了。
@Composable
fun TodoScreen(screen: Screen) {
// Circuit 的状态管理非常优雅
val state by screen.stateFlow.collectAsState()
when (val screen = screen) {
is TodoScreen -> {
TodoView(
state = state.todos,
onAdd = { text -> screen.intent(AddTodo(text)) }
)
}
}
}
Voyager 这个导航库真的拯救了很多多模块项目。它支持组合式导航,这意味着你可以在不同的模块之间自由跳转,完全不需要关注路由是怎么注册的。用起他来比 Navigating with Jetpack Compose 简单太多了。
// Voyager 的导航声明特别直观
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Route.Home
) {
composable<Route.Home> {
HomeScreen(
onNavigateToDetail = { navController.navigate(Route.Detail(it)) }
)
}
composable<Route.Detail> { backStackEntry ->
val detailId = backStackEntry.arguments?.getString("id") ?: return@composable
DetailScreen(detailId = detailId)
}
}
UI 组件篇
Compose Material 3 是 Jetpack Compose 的官方组件库,Google 官方出品,质量绝对有保障。Material You 是 Android 12 引入的动态色彩主题系统,它会自动读取用户的壁纸颜色,然后生成一套协调的主题色。
// Material 3 的主题配置
val colorScheme = when (dynamicColor) {
true -> {
val context = LocalContext.current
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
dynamicDarkColorScheme(context)
} else {
DarkColorScheme
}
}
false -> DarkColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes
) {
Surface(modifier = Modifier.fillMaxSize()) {
YourAppContent()
}
}
Lottie-Android 是 Airbnb 开源的 AE 动画渲染引擎,它可以直接把 After Effects 导出的动画在 Android 上跑起来。这对设计师和开发者的配合简直是福音——设计师在 AE 里做好动画,导出 JSON 文件,开发者直接拿来用。
// Lottie 的使用超级简单
LottieAnimationView(context)
.apply {
setAnimationFromUrl("https://example.com/animation.json")
loop = true
playAnimation()
}
.also { view ->
// 你可以在代码里动态控制动画
view.setProgress(0.5f) // 跳到50%的位置
view.setProgress(0.0f) // 回到开头
}
Compose Multiplatform 是 JetBrains 推出的跨平台 Compose 框架,它让你可以用同一套 UI 代码在 Android、iOS、Desktop 甚至 Web 上运行。对于想要一套代码多端运行的团队来说,这绝对是个神器。
// Compose Multiplatform 的跨平台代码
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
// 这段代码在 Android、iOS、Desktop 都能跑,无需修改
@Composable
fun App() {
Column(modifier = Modifier.fillMaxSize()) {
Greeting("World")
Button(onClick = { /* 点击事件 */ }) {
Text("点击我")
}
}
}
网络与数据篇
Ktor 是 JetBrains 出的异步网络框架,它既可以在服务器端使用,也可以在客户端使用。如果你在 Android 项目里想用一个既轻量又强大的网络库,Ktor 绝对值得考虑。
// 使用 Ktor 进行网络请求
val client = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(json = Json {
ignoreUnknownKeys = true
})
}
}
// 简单的 GET 请求
val user: User = client.get("https://api.example.com/users/123")
// 带参数的 POST 请求
val response = client.post<User>("https://api.example.com/users") {
body = CreateUserRequest(
name = "张三",
email = "zhangsan@example.com"
)
}
Room 是 Google 官方推荐的本地数据库 ORM,它建立在 SQLite 之上,提供了编译时检查,这样你在写 SQL 的时候就能发现错误,而不是等到运行时才爆出来。
// 定义数据实体
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val email: String
)
// 定义 DAO
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
@Delete
suspend fun delete(user: User)
}
// 在 ViewModel 中使用
class UserViewModel(application: Application) : AndroidViewModel(application) {
private val userDao = AppDatabase.getDatabase(application).userDao()
val allUsers: LiveData<List<User>> = userDao.getAll().asLiveData()
fun insertUser(user: User) {
viewModelScope.launch {
userDao.insert(user)
}
}
}
DataStore 是 Google 推出的新一代数据持久化方案,用来替代 SharedPreferences。它支持两种类型:Preferences DataStore 用于存储键值对,Proto DataStore 用于存储强类型对象。
// Preferences DataStore 的使用
class SettingsRepository(private val context: Context) {
private val dataStore: DataStore<Preferences> = context.dataStore(
fileName = "settings.pb"
)
val themeMode: Flow<ThemeMode> = dataStore.data
.map { preferences ->
when (preferences[THEME_MODE_KEY]) {
"dark" -> ThemeMode.Dark
"light" -> ThemeMode.Light
else -> ThemeMode.System
}
}
suspend fun setThemeMode(theme: ThemeMode) {
dataStore.edit { preferences ->
preferences[THEME_MODE_KEY] = when (theme) {
ThemeMode.Dark -> "dark"
ThemeMode.Light -> "light"
ThemeMode.System -> "system"
}
}
}
}
Gson 和 Moshi 是两种常用的 JSON 解析库。Moshi 在 Android 上更受欢迎,因为它支持 Kotlin,而且有编译时校验。
// Moshi 的使用
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val adapter = moshi.adapter<UserJson::class.java)
val user = adapter.fromJson(jsonString)
// 数据类
data class UserJson(
val id: Int,
val name: String,
val email: String?
)
测试篇
Turbine 是一个用于测试 Flow 的工具库,它让异步流测试变得非常简单。以前测试 Flow 需要写一堆复杂的协程代码,现在 Turbine 提供了清晰的断言 API。
// 使用 Turbine 测试 Flow
@Test
fun `用户列表加载测试`() = runTest {
val vm = TodoViewModel(repository)
// 模拟用户加载
vm.intent(TodoIntent.LoadTodos("user123"))
// 验证状态变化
vm.state.test {
// 初始状态
expectItem().apply {
assertThat(isLoading).isTrue()
}
// 加载完成
expectItem().apply {
assertThat(isLoading).isFalse()
assertThat(todos.size).isEqualTo(3)
}
}
}
// 测试错误状态
@Test
fun `网络错误测试`() = runTest {
val vm = TodoViewModel(failingRepository)
vm.state.test {
expectItem().apply {
assertThat(error).isNotNull()
}
}
}
MockK 是 Kotlin 专用的 Mock 框架,它的语法比 Mockito 简洁很多,而且对 Kotlin 的语法特性支持得更好。
// MockK 的使用
class UserViewModelTest {
private val userRepository = mockk<UserRepository>()
private val viewModel = UserViewModel(userRepository)
@Test
fun `测试用户加载`() = runTest {
// 模拟 Repository 返回数据
val users = listOf(
User(1, "张三", "zhangsan@example.com"),
User(2, "李四", "lisi@example.com")
)
coEvery { userRepository.getUsers() } returns users
// 触发加载
viewModel.loadUsers()
// 验证结果
assertEquals(2, viewModel.users.size)
// 验证 Repository 被调用
coVerify { userRepository.getUsers() }
}
}
Compose Testing 是官方提供的 UI 测试库,它可以让你用声明式的方式编写 Compose UI 测试。
// Compose UI 测试
@ComposableTest
fun testTodoList() {
composeTestRule.setContent {
TodoApp()
}
// 查找并点击按钮
composeTestRule.onNodeWithText("添加任务")
.performClick()
// 验证文本出现
composeTestRule.onNodeWithText("任务已添加")
.assertIsDisplayed()
// 验证列表项
composeTestRule.onNodeWithTag("todo_item_1")
.assertExists()
}
工具与效率篇
ACRA 是一个崩溃报告库,它可以帮助你在应用崩溃时自动收集堆栈跟踪、设备信息、日志等,然后发送到你的服务器或第三方服务。
// ACRA 的配置
@AcraCore(
buildConfigClass = BuildConfig::class,
reportFormat = StringFormat.JSON
)
@AcraDialog(
resToastText = R.string.crash_toast_text
)
class MyApplication : Application()
LeakCanary 是 Square 公司开源的内存泄漏检测工具,它在开发环境下会自动监控 Activity 和 Fragment 的生命周期,一旦发现有泄漏就会弹出提示。
// LeakCanary 的使用
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
LeakCanary.install(this)
}
}
// 如果发现泄漏,会在调试时自动通知
// 你只需要在 Android Studio 的 Monitor 里查看即可
Timber 是 Jake Wharton 写的日志框架,它比 Logcat 好用太多。它可以自动打印标签,支持树形结构,还能在 Release 包里自动关闭日志。
// Timber 的使用
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
} else {
// 生产环境使用 Crashlytics 或 ACRA
Timber.plant(object : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
// 发送到远程日志服务
}
})
}
}
}
// 使用非常简单
Timber.d("用户登录成功: %s", userId)
Timber.e(exception, "网络请求失败")
Timber.tag("Network").d("请求完成")
Hilt 是 Google 官方推荐的依赖注入框架,它建立在 Dagger 之上,让依赖注入变得超级简单。
// Hilt 的基本配置
@HiltAndroidApp
class MyApplication : Application()
// 注入依赖
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var userRepository: UserRepository
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// userRepository 和 networkService 已经被注入了
}
}
// 模块定义
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideNetworkService(): NetworkService {
return RetrofitClient.create(NetworkService::class.java)
}
}
热门综合项目篇
ExoPlayer 是 Google 开源的多媒体播放器,它的功能非常强大,支持各种格式的音视频播放,包括 DASH、HLS、SmoothStreaming 等自适应流媒体协议。
// ExoPlayer 的使用
class PlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
private var videoView: SimpleExoPlayerView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
player = ExoPlayer.Builder(this).build()
videoView = findViewById<R.id.player_view)
videoView!!.player = player
val mediaItem = MediaItem.fromUri("https://example.com/video.mp4")
player?.setMediaItem(mediaItem)
player?.prepare()
player?.play()
}
override fun onDestroy() {
super.onDestroy()
videoView?.player = null
player?.release()
}
}
Glide 是 Google 推荐的图片加载库,它支持 GIF、WebP、Video 等多种格式,而且对内存和性能的优化做得非常好。
// Glide 的常用用法
// 基本加载
Glide.with(context)
.load("https://example.com/image.jpg")
.into(imageView)
// 带占位图和错误图
Glide.with(context)
.load(url)
.placeholder(R.drawable.loading)
.error(R.drawable.error)
.into(imageView)
// 圆形图片
Glide.with(context)
.load(url)
.circleCrop()
.into(imageView)
// 自定义 RequestOptions
val options = RequestOptions()
.override(200, 200)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
Glide.with(context)
.load(url)
.apply(options)
.into(imageView)
Retrofit 是 Square 公司开源的 REST 客户端,它的类型安全 API 让网络请求变得超级简单。
// Retrofit 的定义
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: Int): User
@POST("users")
suspend fun createUser(@Body user: CreateUserRequest): User
@GET("posts")
suspend fun getPosts(
@Query("page") page: Int,
@Query("limit") limit: Int
): List<Post>
}
// 创建 Retrofit 实例
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
// 使用
suspend fun fetchUser(userId: Int): User {
return apiService.getUser(userId)
}
OkHttp 是 Square 公司出的网络请求库,它是很多上层库(包括 Retrofit)的底层实现。它支持连接池、请求缓存、拦截器等功能。
// OkHttp 的使用
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor { chain ->
val original = chain.request()
val request = original.newBuilder()
.header("Authorization", "Bearer token")
.method(original.method, original.body)
.build()
chain.proceed(request)
}
.build()
// GET 请求
val request = Request.Builder()
.url("https://api.example.com/users")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
val body = response.body?.string()
// 处理响应
}
})
这些开源项目都是经过无数开发者验证的精品,掌握它们能让你的 Android 开发之路顺畅很多。每个项目都有它的适用场景,不要盲目追求最新最热,而是要根据项目的实际需求来选择。比如,如果你的项目需要严格的架构约束,那就选 MVIKotlin;如果只是想快速开发,那 Hilt + Room 的组合就足够了。希望这份指南能帮到你!
