Android Development with Kotlin — Usage Guide

举报
yd_217846120 发表于 2026/09/02 09:09:24 2026/09/02
【摘要】 Android Development with Kotlin — Usage Guide 1. IntroductionKotlin is the officially recommended language for Android development. It is concise, null-safe, interoperable with Java, and fully sup...

Android Development with Kotlin — Usage Guide

1. Introduction

Kotlin is the officially recommended language for Android development. It is concise, null-safe, interoperable with Java, and fully supported by Android Studio, Jetpack libraries, and the Gradle build system. This guide covers the core language features, project setup, common patterns, Jetpack Compose UI, and best practices you will use day to day.


2. Language Essentials

2.1 Variables

val immutable: String = "cannot be reassigned"
var mutable: Int = 0
mutable = 1

// Type inference
val name = "Kotlin"      // String
val count = 42           // Int
val pi = 3.14            // Double

Prefer val over var. Use var only when the value must change.

2.2 Null Safety

var nullable: String? = null
var nonNull: String = "always set"

// Safe call
val length: Int? = nullable?.length

// Elvis operator — fallback when null
val safeLength: Int = nullable?.length ?: 0

// Not-null assertion — use sparingly
val forced: Int = nullable!!.length

// Smart cast after null check
if (nullable != null) {
    println(nullable.length) // treated as non-null here
}

2.3 Strings

val user = "Ada"
val greeting = "Hello, $user!"
val multiline = """
    Line one
    Line two
""".trimIndent()

2.4 Collections

val list = listOf(1, 2, 3)              // read-only
val mutableList = mutableListOf(1, 2, 3)
val set = setOf("a", "b", "a")          // [a, b]
val map = mapOf("key" to "value")

// Functional operations
val doubled = list.map { it * 2 }
val evens = list.filter { it % 2 == 0 }
val sum = list.reduce { acc, n -> acc + n }

2.5 Control Flow

// if as expression
val max = if (a > b) a else b

// when (replaces switch)
val description = when (x) {
    0 -> "zero"
    in 1..9 -> "single digit"
    is Int -> "integer"
    else -> "other"
}

// ranges
for (i in 1..10) print(i)
for (i in 10 downTo 1 step 2) print(i)

3. Functions and Lambdas

fun add(a: Int, b: Int): Int = a + b

// Default and named arguments
fun greet(name: String, greeting: String = "Hello") = "$greeting, $name!"
greet(name = "Ada")
greet("Ada", greeting = "Hi")

// Vararg
fun sum(vararg numbers: Int): Int = numbers.sum()

// Lambda
val square: (Int) -> Int = { x -> x * x }
val shortSquare: (Int) -> Int = { it * it }

// Higher-order function
fun applyTwice(x: Int, f: (Int) -> Int): Int = f(f(x))

4. Classes and Objects

4.1 Data Classes

data class User(val id: Long, val name: String, val email: String? = null)

val u1 = User(1, "Ada")
val u2 = u1.copy(name = "Grace")
println(u1 == u2) // structural equality

4.2 Regular and Open Classes

open class Animal(val name: String) {
    open fun sound(): String = "unknown"
}

class Dog(name: String) : Animal(name) {
    override fun sound() = "bark"
}

4.3 Sealed Classes

Useful for representing restricted hierarchies, especially UI state.

sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String) : UiState<Nothing>()
}

fun render(state: UiState<String>) = when (state) {
    is UiState.Loading -> "loading"
    is UiState.Success -> state.data
    is UiState.Error -> state.message
}

4.4 Object and Companion

object AppConfig {
    const val VERSION = "1.0"
}

class Logger private constructor() {
    companion object {
        fun create() = Logger()
    }
}

4.5 Enum

enum class Direction(val degrees: Int) {
    NORTH(0), EAST(90), SOUTH(180), WEST(270)
}

5. Coroutines and Asynchrony

Coroutines are the standard way to handle async work on Android.

import kotlinx.coroutines.*

// Launch a coroutine
GlobalScope.launch {
    delay(1000)
    println("done")
}

// Suspend function
suspend fun fetchUser(id: Long): User {
    delay(500)
    return User(id, "Ada")
}

// Structured concurrency
suspend fun loadAll(): List<User> = coroutineScope {
    val a = async { fetchUser(1) }
    val b = async { fetchUser(2) }
    listOf(a.await(), b.await())
}

5.1 Dispatchers

Dispatchers.Main      // UI thread
Dispatchers.IO        // network / database
Dispatchers.Default   // CPU-heavy

5.2 Flow

fun countdown(): Flow<Int> = flow {
    for (i in 5 downTo 1) {
        emit(i)
        delay(200)
    }
}

// Collect
countdown().collect { value -> println(value) }

6. Project Setup

6.1 Gradle (Kotlin DSL)

build.gradle.kts (module):

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.plugin.compose")
}

android {
    namespace = "com.example.app"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }

    buildFeatures {
        compose = true
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
}

dependencies {
    implementation(platform("androidx.compose:compose-bom:2024.06.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.activity:activity-compose:1.9.0")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")
}

6.2 Application Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:name=".App"
        android:label="@string/app_name"
        android:theme="@style/Theme.App">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

7. Jetpack Compose UI

Compose is the modern declarative UI toolkit for Android.

7.1 Composable Functions

import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.unit.dp

@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

@Composable
fun ProfileCard(name: String, onClick: () -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(text = name, style = MaterialTheme.typography.headlineSmall)
        Button(onClick = onClick) {
            Text("View")
        }
    }
}

7.2 State

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Clicked $count times")
    }
}

7.3 Side Effects

@Composable
fun Loader(viewModel: MyViewModel) {
    LaunchedEffect(Unit) {
        viewModel.load()
    }
    // ...
}

7.4 Lists

@Composable
fun UserList(users: List<User>) {
    LazyColumn {
        items(users) { user ->
            ProfileCard(name = user.name, onClick = { /* ... */ })
        }
    }
}

7.5 Theme

@Composable
fun AppTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        colorScheme = lightColorScheme(),
        typography = Typography(),
        content = content
    )
}

8. ViewModel and State

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*

class UserViewModel : ViewModel() {
    private val _state = MutableStateFlow<UiState<List<User>>>(UiState.Loading)
    val state: StateFlow<UiState<List<User>>> = _state

    fun load() {
        viewModelScope.launch {
            _state.value = UiState.Loading
            try {
                val users = repository.fetchUsers()
                _state.value = UiState.Success(users)
            } catch (e: Exception) {
                _state.value = UiState.Error(e.message ?: "unknown")
            }
        }
    }
}

8.1 Collecting State in Compose

@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
    val state by viewModel.state.collectAsState()
    when (val s = state) {
        is UiState.Loading -> CircularProgressIndicator()
        is UiState.Success -> UserList(s.data)
        is UiState.Error -> Text("Error: ${s.message}")
    }
}

9. Dependency Injection with Hilt

import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject

@HiltAndroidApp
class App : Application()

class UserRepository @Inject constructor() {
    suspend fun fetchUsers(): List<User> = emptyList()
}

@HiltViewModel
class UserViewModel @Inject constructor(
    private val repository: UserRepository
) : ViewModel() { /* ... */ }

10. Networking with Retrofit

import retrofit2.http.GET
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

val api = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(ApiService::class.java)

11. Room Database

import androidx.room.*

@Entity
data class UserEntity(
    @PrimaryKey val id: Long,
    val name: String
)

@Dao
interface UserDao {
    @Query("SELECT * FROM UserEntity")
    fun observeAll(): Flow<List<UserEntity>>

    @Insert
    suspend fun insert(user: UserEntity)
}

@Database(entities = [UserEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

12. Permissions

import android.Manifest
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts

@Composable
fun CameraScreen() {
    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { granted ->
        if (granted) { /* open camera */ }
    }
    Button(onClick = { launcher.launch(Manifest.permission.CAMERA) }) {
        Text("Grant camera")
    }
}

13. Navigation Compose

import androidx.navigation.compose.*

@Composable
fun AppNav() {
    val nav = rememberNavController()
    NavHost(navController = nav, startDestination = "home") {
        composable("home") { HomeScreen(onNavigate = { nav.navigate("detail") }) }
        composable("detail") { DetailScreen() }
    }
}

14. Error Handling

suspend fun safeCall(block: suspend () -> String): Result<String> = try {
    Result.success(block())
} catch (e: CancellationException) {
    throw e
} catch (e: Throwable) {
    Result.failure(e)
}

Always rethrow CancellationException to preserve coroutine cancellation.


15. Testing

15.1 Unit Test

import org.junit.Test
import org.junit.Assert.*

class CalculatorTest {
    @Test
    fun adds_correctly() {
        assertEquals(4, Calculator.add(2, 2))
    }
}

15.2 Coroutine Test

import kotlinx.coroutines.test.*
import org.junit.Test

class ViewModelTest {
    @Test
    fun loads_users() = runTest {
        val vm = UserViewModel(FakeRepository())
        vm.load()
        assertEquals(UiState.Success(listOf<User>()), vm.state.value)
    }
}

16. Best Practices

  1. Prefer val and immutability; use data class for models.
  2. Never ignore nullability — let the type system guide you.
  3. Use coroutines and Flow instead of callbacks and Thread.
  4. Keep business logic out of composables; put it in ViewModel.
  5. Use StateFlow for UI state and collect it with collectAsState().
  6. Scope coroutines to viewModelScope or lifecycleScope.
  7. Use sealed class to model state, results, and one-shot events.
  8. Avoid GlobalScope in app code.
  9. Enable R8/ProGuard minification for release builds.
  10. Write tests for ViewModels and repositories; keep composables thin.

17. Common Pitfalls

  • Using !! broadly — prefer ?: or explicit null checks.
  • Blocking the main thread with Thread.sleep or synchronous I/O.
  • Forgetting runTest when testing suspend functions.
  • Holding context references in singletons — risk of leaks.
  • Mutating state outside of MutableStateFlow updates.
  • Recomposing too often — hoist stable state and use remember/derivedStateOf.

18. Quick Reference

Need Use
Immutable model data class
Restricted hierarchy sealed class
UI state StateFlow + collectAsState
Async work viewModelScope.launch
Streams Flow / StateFlow
DI Hilt
Database Room
Networking Retrofit + Coroutines
Navigation Navigation Compose
Permissions ActivityResultContracts

This guide covers the core building blocks of modern Android development with Kotlin and Jetpack Compose. Start with sections 2 through 5 to internalize the language, then build UI with section 7, and wire up data with sections 8 through 11.

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。