2-2-45 快速掌握Kotlin-使用 Kotlin 注意事项点

16 阅读4分钟

Android 开发使用 Kotlin 注意事项点

一、空安全与平台类型

1. 正确处理 Android SDK 的可空性

// ❌ 危险:直接使用可能为 null 的 SDK 返回值
fun dangerousGetView(): View {
    return findViewById(R.id.my_view) // 编译警告:类型不匹配
}

// ✅ 安全:处理可空性
fun safeGetView(): View? {
    return findViewById(R.id.my_view)
}

// ✅ 使用非空断言(确定不为 null 时)
fun getViewWithAssert(): View {
    return findViewById(R.id.my_view)!!
}

// ✅ 使用 Elvis 操作符提供默认值
fun getViewOrDefault(): View {
    return findViewById(R.id.my_view) ?: createDefaultView()
}

// ✅ 安全调用
fun setupView() {
    val view = findViewById<View?>(R.id.my_view)
    view?.setOnClickListener {
        // 安全的点击处理
    }
}

2. 使用 lateinit 的注意事项

class MainActivity : AppCompatActivity() {
    // ✅ 正确使用 lateinit
    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: MyAdapter
    private lateinit var viewModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 必须在访问前初始化
        recyclerView = findViewById(R.id.recycler_view)
        adapter = MyAdapter()
        recyclerView.adapter = adapter
        
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
    }
    
    // ❌ 错误:在初始化前访问
    fun riskyMethod() {
        // recyclerView.layoutManager = LinearLayoutManager(this) // 会抛出异常
    }
    
    // ✅ 检查是否已初始化
    fun safeMethod() {
        if (::recyclerView.isInitialized) {
            recyclerView.layoutManager = LinearLayoutManager(this)
        }
    }
}

二、生命周期管理

1. 避免在生命周期回调中泄露

class MyActivity : AppCompatActivity() {
    private val disposables = CompositeDisposable()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ❌ 错误:可能泄露的 RxJava 订阅
        Observable.interval(1, TimeUnit.SECONDS)
            .subscribe { /* ... */ } // 没有清理
        
        // ✅ 正确:管理订阅生命周期
        Observable.interval(1, TimeUnit.SECONDS)
            .subscribe { /* ... */ }
            .addTo(disposables)
    }
    
    override fun onDestroy() {
        disposables.clear() // 清理所有订阅
        super.onDestroy()
    }
}

2. 使用 ViewModel 和 LiveData

class MainViewModel : ViewModel() {
    // ✅ 使用 LiveData 观察数据变化
    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> get() = _users
    
    // ✅ 使用 ViewModelScope 管理协程
    fun loadUsers() {
        viewModelScope.launch {
            try {
                val result = repository.getUsers()
                _users.value = result
            } catch (e: Exception) {
                // 处理错误
            }
        }
    }
    
    // ❌ 错误:直接暴露 MutableLiveData
    // val users = MutableLiveData<List<User>>()
    
    // ✅ 封装数据更新
    fun updateUser(user: User) {
        _users.value = _users.value?.map {
            if (it.id == user.id) user else it
        }
    }
}

class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ✅ 观察 LiveData
        viewModel.users.observe(this) { users ->
            // 更新 UI
            adapter.submitList(users)
        }
        
        // ❌ 错误:在 onStop 之后更新 UI
        // viewModel.users.observe(this) { users ->
        //     textView.text = "Users: ${users.size}"
        // }
    }
}

三、协程使用

1. 正确管理协程作用域

class MyFragment : Fragment() {
    // ❌ 错误:直接使用 GlobalScope
    // GlobalScope.launch { /* ... */ }
    
    // ✅ 正确:使用 lifecycleScope 或 viewLifecycleOwner.lifecycleScope
    fun loadData() {
        viewLifecycleOwner.lifecycleScope.launch {
            val data = withContext(Dispatchers.IO) {
                repository.fetchData()
            }
            updateUI(data)
        }
    }
    
    // ✅ 结构化并发
    fun structuredConcurrency() {
        lifecycleScope.launch {
            try {
                val deferred1 = async { fetchUser() }
                val deferred2 = async { fetchPosts() }
                
                val user = deferred1.await()
                val posts = deferred2.await()
                
                // 处理结果
            } catch (e: Exception) {
                // 统一处理异常
            }
        }
    }
    
    // ✅ 超时处理
    fun withTimeout() {
        lifecycleScope.launch {
            try {
                val result = withTimeout(5000) {
                    fetchSlowData()
                }
                // 处理结果
            } catch (e: TimeoutCancellationException) {
                showTimeoutError()
            }
        }
    }
}

2. 线程切换与 Dispatchers

suspend fun fetchData(): Result<Data> {
    // ❌ 错误:在主线程执行 IO 操作
    // return repository.getData()
    
    // ✅ 正确:切换到 IO 线程
    return withContext(Dispatchers.IO) {
        repository.getData()
    }
}

fun processData() {
    lifecycleScope.launch {
        // UI 线程:更新 UI
        showLoading()
        
        try {
            // IO 线程:网络请求
            val data = withContext(Dispatchers.IO) {
                repository.fetchData()
            }
            
            // Default 线程:处理数据
            val processedData = withContext(Dispatchers.Default) {
                processLargeData(data)
            }
            
            // UI 线程:更新结果
            withContext(Dispatchers.Main) {
                showData(processedData)
            }
        } catch (e: Exception) {
            withContext(Dispatchers.Main) {
                showError(e)
            }
        } finally {
            withContext(Dispatchers.Main) {
                hideLoading()
            }
        }
    }
}

四、扩展函数与属性

1. 创建实用的扩展函数

// ✅ View 扩展函数
fun View.show() {
    visibility = View.VISIBLE
}

fun View.hide() {
    visibility = View.GONE
}

fun View.invisible() {
    visibility = View.INVISIBLE
}

// ✅ Context 扩展函数
fun Context.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}

fun Context.dpToPx(dp: Int): Float {
    return dp * resources.displayMetrics.density
}

// ✅ Fragment 扩展函数
fun Fragment.showDialog(
    title: String,
    message: String,
    positiveAction: () -> Unit = {}
) {
    MaterialAlertDialogBuilder(requireContext())
        .setTitle(title)
        .setMessage(message)
        .setPositiveButton("确定") { _, _ -> positiveAction() }
        .setNegativeButton("取消", null)
        .show()
}

// ✅ RecyclerView 扩展
fun RecyclerView.setup(
    layoutManager: RecyclerView.LayoutManager,
    adapter: RecyclerView.Adapter<*>,
    divider: RecyclerView.ItemDecoration? = null
) {
    this.layoutManager = layoutManager
    this.adapter = adapter
    divider?.let { addItemDecoration(it) }
}

2. 避免过度使用扩展函数

// ❌ 不好:过度封装
fun String.toBitmap(): Bitmap? { /* ... */ }

// ✅ 好:合理的扩展
val String.md5: String
    get() = try {
        val digest = MessageDigest.getInstance("MD5")
        val bytes = digest.digest(toByteArray())
        bytes.joinToString("") { "%02x".format(it) }
    } catch (e: NoSuchAlgorithmException) {
        ""
    }

// ❌ 不好:修改全局行为
fun List<Any>.logAll() {
    forEach { println(it) }
}

// ✅ 好:特定类型的扩展
fun List<User>.logUserNames() {
    forEach { println(it.name) }
}

五、数据类与密封类

1. 数据类的正确使用

// ✅ 网络响应数据类
data class ApiResponse<T>(
    val success: Boolean,
    val data: T?,
    val error: String?,
    val code: Int
) {
    // 添加业务逻辑方法
    fun isSuccessful(): Boolean = success && data != null
    
    fun getErrorOrNull(): String? = if (!success) error else null
}

// ✅ UI 状态数据类
data class LoginState(
    val isLoading: Boolean = false,
    val isSuccess: Boolean = false,
    val error: String? = null,
    val user: User? = null
) {
    // 定义状态转换方法
    fun loading() = copy(isLoading = true, error = null)
    fun success(user: User) = copy(isLoading = false, isSuccess = true, user = user)
    fun error(message: String) = copy(isLoading = false, error = message)
}

// ❌ 错误:在数据类中使用可变集合
data class BadUser(
    val name: String,
    val permissions: MutableList<String> // 可能导致意外修改
)

// ✅ 正确:使用不可变集合
data class GoodUser(
    val name: String,
    val permissions: List<String>
) {
    // 提供修改副本的方法
    fun addPermission(permission: String): GoodUser {
        return copy(permissions = permissions + permission)
    }
}

2. 密封类处理状态和事件

// ✅ UI 状态密封类
sealed class Resource<out T> {
    object Loading : Resource<Nothing>()
    data class Success<out T>(val data: T) : Resource<T>()
    data class Error(val exception: Throwable) : Resource<Nothing>()
}

// ✅ 事件密封类(用于一次性事件)
sealed class Event {
    data class ShowToast(val message: String) : Event()
    data class NavigateTo(val destination: String) : Event()
    object ShowLoading : Event()
    object HideLoading : Event()
}

// 在 ViewModel 中使用
class MyViewModel : ViewModel() {
    private val _events = Channel<Event>()
    val events = _events.receiveAsFlow()
    
    fun performAction() {
        viewModelScope.launch {
            _events.send(Event.ShowLoading)
            try {
                // 执行操作
                _events.send(Event.NavigateTo("success"))
            } catch (e: Exception) {
                _events.send(Event.ShowToast(e.message ?: "错误"))
            } finally {
                _events.send(Event.HideLoading)
            }
        }
    }
}

// 在 Activity/Fragment 中观察
viewModel.events.onEach { event ->
    when (event) {
        is Event.ShowToast -> showToast(event.message)
        is Event.NavigateTo -> navigateTo(event.destination)
        Event.ShowLoading -> showLoading()
        Event.HideLoading -> hideLoading()
    }
}.launchIn(lifecycleScope)

六、集合操作与性能

1. 使用序列优化性能

// ❌ 性能差:多个中间集合
fun processLargeList(list: List<Data>): List<Result> {
    return list
        .filter { it.isValid() }        // 中间集合1
        .map { it.transform() }         // 中间集合2
        .filter { it.isReady() }        // 中间集合3
        .sortedBy { it.priority }       // 中间集合4
        .take(100)                      // 中间集合5
}

// ✅ 性能好:使用序列(惰性求值)
fun processLargeListEfficiently(list: List<Data>): List<Result> {
    return list.asSequence()
        .filter { it.isValid() }
        .map { it.transform() }
        .filter { it.isReady() }
        .sortedBy { it.priority }
        .take(100)
        .toList()
}

// ✅ 流式处理
fun processDataStream(dataList: List<Data>): Flow<Result> {
    return dataList.asFlow()
        .filter { it.isValid() }
        .map { it.transform() }
        .onEach { /* 边处理边更新 UI */ }
        .flowOn(Dispatchers.Default)
}

2. 避免重复计算

// ❌ 不好:重复计算
fun updateUI(data: List<User>) {
    val activeUsers = data.filter { it.isActive }
    val inactiveUsers = data.filter { !it.isActive }
    
    // 过滤了两次
}

// ✅ 好:使用 partition
fun updateUI(data: List<User>) {
    val (activeUsers, inactiveUsers) = data.partition { it.isActive }
    // 只过滤一次
}

// ❌ 不好:重复转换
fun processItems(items: List<String>) {
    val upperItems = items.map { it.uppercase() }
    val lowerItems = items.map { it.lowercase() }
    
    // 转换了两次
}

// ✅ 好:缓存转换结果
fun processItems(items: List<String>) {
    val transformedItems = items.map { 
        Pair(it.uppercase(), it.lowercase())
    }
    
    val upperItems = transformedItems.map { it.first }
    val lowerItems = transformedItems.map { it.second }
}

七、内存管理与泄漏

1. 避免常见的内存泄漏

class MyActivity : AppCompatActivity() {
    
    // ❌ 错误:Activity 上下文传递给长生命周期对象
    private val apiClient = ApiClient(this) // 持有 Activity 引用
    
    // ✅ 正确:使用 Application 上下文
    private val apiClient = ApiClient(applicationContext)
    
    // ❌ 错误:匿名内部类持有外部引用
    private val callback = object : SomeCallback {
        override fun onResult() {
            // 隐式持有 MyActivity 引用
            doSomething()
        }
    }
    
    // ✅ 正确:使用弱引用或静态内部类
    private val callback = WeakCallback(this)
    
    class WeakCallback(activity: MyActivity) : SomeCallback {
        private val weakActivity = WeakReference(activity)
        
        override fun onResult() {
            weakActivity.get()?.doSomething()
        }
    }
}

// ✅ 使用 ViewBinding 避免泄漏
class MainFragment : Fragment() {
    private var _binding: FragmentMainBinding? = null
    private val binding get() = _binding!!
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null // 解除绑定,避免内存泄漏
    }
}

2. 正确使用 by lazy

class MyFragment : Fragment() {
    // ✅ 正确:在生命周期合适的时候初始化
    private val viewModel: MainViewModel by lazy {
        ViewModelProvider(this).get(MainViewModel::class.java)
    }
    
    // ✅ 正确:只读视图引用
    private val recyclerView: RecyclerView by lazy {
        requireView().findViewById(R.id.recycler_view)
    }
    
    // ❌ 错误:可能访问未创建视图
    // private val button: Button by lazy {
    //     requireView().findViewById(R.id.button)
    // }
    
    // ✅ 正确:使用 viewLifecycleOwner
    private val adapter: MyAdapter by lazy {
        MyAdapter().apply {
            // 初始化配置
        }
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 安全初始化
        recyclerView.adapter = adapter
    }
}

八、构建器模式与 DSL

1. 使用 DSL 简化 UI 构建

// 创建 RecyclerView DSL
fun RecyclerView.setup(config: RecyclerViewConfig.() -> Unit) {
    val configObj = RecyclerViewConfig().apply(config)
    
    layoutManager = configObj.layoutManager
    adapter = configObj.adapter
    
    configObj.itemDecoration?.let { addItemDecoration(it) }
    configObj.itemAnimator?.let { itemAnimator = it }
}

class RecyclerViewConfig {
    var layoutManager: RecyclerView.LayoutManager? = null
    var adapter: RecyclerView.Adapter<*>? = null
    var itemDecoration: RecyclerView.ItemDecoration? = null
    var itemAnimator: RecyclerView.ItemAnimator? = null
}

// 使用示例
recyclerView.setup {
    layoutManager = LinearLayoutManager(context)
    adapter = MyAdapter()
    itemDecoration = DividerItemDecoration(context, LinearLayoutManager.VERTICAL)
}

2. Intent 构建器

// Intent 扩展函数
inline fun <reified T : Activity> Context.intentOf(
    vararg pairs: Pair<String, Any?>
): Intent {
    return Intent(this, T::class.java).apply {
        pairs.forEach { (key, value) ->
            when (value) {
                is Int -> putExtra(key, value)
                is String -> putExtra(key, value)
                is Parcelable -> putExtra(key, value)
                is Serializable -> putExtra(key, value)
                // 添加其他类型支持
            }
        }
    }
}

// 使用示例
val intent = intentOf<DetailActivity>(
    "id" to item.id,
    "name" to item.name,
    "data" to item.data
)
startActivity(intent)

九、测试注意事项

1. 编写可测试的代码

// ❌ 难以测试
class BadViewModel {
    fun loadData() {
        GlobalScope.launch {
            val data = ApiService.getInstance().getData()
            // 直接使用,难以 mock
        }
    }
}

// ✅ 易于测试
class GoodViewModel(
    private val repository: DataRepository,
    private val dispatcher: CoroutineDispatcher = Dispatchers.Main
) : ViewModel() {
    
    private val _data = MutableLiveData<Resource<Data>>()
    val data: LiveData<Resource<Data>> = _data
    
    fun loadData() {
        viewModelScope.launch(dispatcher) {
            _data.value = Resource.Loading
            try {
                val result = withContext(Dispatchers.IO) {
                    repository.getData()
                }
                _data.value = Resource.Success(result)
            } catch (e: Exception) {
                _data.value = Resource.Error(e)
            }
        }
    }
}

// 测试代码
@Test
fun testLoadDataSuccess() = runTest {
    val mockRepository = mockk<DataRepository>()
    coEvery { mockRepository.getData() } returns testData
    
    val viewModel = GoodViewModel(mockRepository, testDispatcher)
    
    viewModel.loadData()
    
    val result = viewModel.data.getOrAwaitValue()
    assertTrue(result is Resource.Success)
}

2. 使用依赖注入

// 使用 Koin 依赖注入
val appModule = module {
    single { createApiService() }
    single<DataRepository> { DataRepositoryImpl(get()) }
    viewModel { MainViewModel(get()) }
}

// 或者使用 Hilt
@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: DataRepository
) : ViewModel() {
    // ...
}

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    // ...
}

十、资源管理

1. 正确使用字符串资源

// ❌ 硬编码字符串
textView.text = "欢迎回来,${user.name}!"

// ✅ 使用字符串资源
// strings.xml
// <string name="welcome_back">欢迎回来,%s!</string>

textView.text = getString(R.string.welcome_back, user.name)

// ✅ 复数处理
// <plurals name="item_count">
//     <item quantity="one">%d 个项目</item>
//     <item quantity="other">%d 个项目</item>
// </plurals>

val itemCount = items.size
textView.text = resources.getQuantityString(R.plurals.item_count, itemCount, itemCount)

2. Bitmap 和资源释放

// Bitmap 处理
fun loadBitmapSafely(context: Context, @DrawableRes resId: Int): Bitmap? {
    return try {
        val options = BitmapFactory.Options().apply {
            inPreferredConfig = Bitmap.Config.RGB_565
            inSampleSize = 2 // 缩小采样
        }
        BitmapFactory.decodeResource(context.resources, resId, options)
    } catch (e: OutOfMemoryError) {
        // 处理内存不足
        null
    }
}

// 及时回收 Bitmap
fun cleanupBitmaps(bitmaps: List<Bitmap?>) {
    bitmaps.forEach { bitmap ->
        bitmap?.apply {
            if (!isRecycled) {
                recycle()
            }
        }
    }
}

// 使用 use 自动关闭资源
fun readFileSafely(path: String): String? {
    return try {
        File(path).bufferedReader().use { reader ->
            reader.readText()
        }
    } catch (e: Exception) {
        null
    }
}

十一、版本兼容性

1. API 版本检查

// 检查 API 版本
fun setupFeatures() {
    // ✅ 使用版本检查
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // 使用新 API
        setupNotificationChannel()
    } else {
        // 回退方案
        setupLegacyNotifications()
    }
    
    // ✅ 使用 @RequiresApi 注解
    @RequiresApi(Build.VERSION_CODES.N)
    fun newApiMethod() {
        // 需要特定版本
    }
    
    // ✅ 使用扩展函数封装版本检查
    fun Context.createShortcutCompat() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createShortcut()
        }
    }
}

// 权限检查
fun checkAndRequestPermissions() {
    val requiredPermissions = arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.ACCESS_FINE_LOCATION
    )
    
    val missingPermissions = requiredPermissions.filter {
        ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
    }
    
    if (missingPermissions.isNotEmpty()) {
        ActivityCompat.requestPermissions(
            this,
            missingPermissions.toTypedArray(),
            PERMISSION_REQUEST_CODE
        )
    }
}

十二、性能优化

1. RecyclerView 优化

class MyAdapter : ListAdapter<Item, MyViewHolder>(DiffCallback()) {
    
    // ✅ 使用 DiffUtil 高效更新
    class DiffCallback : DiffUtil.ItemCallback<Item>() {
        override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
            return oldItem.id == newItem.id
        }
        
        override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
            return oldItem == newItem
        }
    }
    
    // ✅ 避免在 onBindViewHolder 中创建对象
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = getItem(position)
        
        // ❌ 不好:每次创建新监听器
        // holder.button.setOnClickListener { /* ... */ }
        
        // ✅ 好:复用监听器
        holder.bind(item, clickListener)
    }
    
    // ✅ 使用 payloads 部分更新
    override fun onBindViewHolder(
        holder: MyViewHolder,
        position: Int,
        payloads: List<Any>
    ) {
        if (payloads.isEmpty()) {
            onBindViewHolder(holder, position)
        } else {
            // 部分更新逻辑
            payloads.forEach { payload ->
                if (payload is ItemUpdate) {
                    holder.updatePartially(payload)
                }
            }
        }
    }
}

2. 避免主线程阻塞

// 使用 WorkManager 处理后台任务
fun scheduleBackgroundWork() {
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build()
    
    val workRequest = OneTimeWorkRequestBuilder<SyncWorker>()
        .setConstraints(constraints)
        .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
        .build()
    
    WorkManager.getInstance(applicationContext)
        .enqueueUniqueWork("sync", ExistingWorkPolicy.KEEP, workRequest)
}

// 使用 IntentService 的替代方案
class MyWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    
    override suspend fun doWork(): Result {
        return try {
            // 执行后台任务
            performLongRunningTask()
            Result.success()
        } catch (e: Exception) {
            if (runAttemptCount < MAX_RETRY) {
                Result.retry()
            } else {
                Result.failure()
            }
        }
    }
    
    private suspend fun performLongRunningTask() {
        // 耗时操作
        delay(5000)
    }
}

十三、错误处理

1. 统一的错误处理

sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    
    val isSuccess: Boolean get() = this is Success<T>
    val isError: Boolean get() = this is Error
    
    fun onSuccess(action: (T) -> Unit): Result<T> {
        if (this is Success) action(data)
        return this
    }
    
    fun onError(action: (Exception) -> Unit): Result<T> {
        if (this is Error) action(exception)
        return this
    }
}

// 使用示例
suspend fun fetchData(): Result<Data> {
    return try {
        val data = apiService.getData()
        Result.Success(data)
    } catch (e: IOException) {
        Result.Error(NetworkException("网络错误", e))
    } catch (e: Exception) {
        Result.Error(e)
    }
}

// 在 ViewModel 中处理
viewModelScope.launch {
    when (val result = repository.fetchData()) {
        is Result.Success -> _data.value = result.data
        is Result.Error -> _error.value = result.exception.message
    }
}

十四、总结要点

必须遵守的 Kotlin Android 开发原则:

  1. 空安全第一:始终正确处理可空类型,避免使用 !!
  2. 生命周期感知:所有异步操作都应与生命周期绑定
  3. 主线程保护:不在主线程执行耗时操作
  4. 内存管理:及时释放资源,避免内存泄漏
  5. 协程优先:使用协程替代回调,但要注意作用域
  6. 不可变数据:优先使用不可变数据和纯函数
  7. 扩展函数适度:合理使用扩展,不要过度设计
  8. 测试驱动:编写可测试的代码结构
  9. 资源优化:正确处理图片和大型资源
  10. 版本兼容:处理好不同 API 级别的兼容性

推荐的架构模式:

View (Activity/Fragment) → ViewModel → Repository → Data Source
     ↑                       ↑             ↑
   LiveData/Flow         CoroutineScope  Retrofit/Room

必备工具和库:

  • Android KTX:官方 Kotlin 扩展
  • Coroutines:异步处理
  • ViewModel & LiveData:生命周期管理
  • Room:数据库
  • Retrofit:网络请求
  • Koin/Hilt:依赖注入
  • Coil/Glide:图片加载