Skip to content
kotlin-expert logo

Kotlin Expert

kotlin-expert

Expert-level Kotlin development, Android, coroutines, and multiplatform

SKILL.md

Full skill instructions

Kotlin Expert

Expert guidance for Kotlin development, Android, coroutines, Kotlin Multiplatform, and modern JVM development.

Core Concepts

Kotlin Fundamentals

  • Null safety
  • Extension functions
  • Data classes
  • Sealed classes
  • Coroutines and Flow
  • Higher-order functions

Android Development

  • Jetpack Compose
  • ViewModel and LiveData
  • Room database
  • Retrofit networking
  • Dependency injection (Hilt)
  • Android lifecycle

Kotlin Multiplatform

  • Shared business logic
  • Platform-specific implementations
  • iOS and Android targets
  • Common module architecture

Modern Kotlin Syntax

// Data classes
data class User(
    val id: String,
    val name: String,
    val email: String,
    val createdAt: LocalDateTime = LocalDateTime.now()
)

// Sealed classes for type-safe states
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// Extension functions
fun String.isValidEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

// Scope functions
fun processUser(user: User) {
    user.run {
        println("Processing user: $name")
        // 'this' refers to user
    }

    user.let { u ->
        // 'it' or custom name refers to user
        println(u.email)
    }

    user.apply {
        // Modify properties
        // Returns the object
    }
}

// Null safety
fun findUser(id: String): User? {
    return database.find(id)
}

val user = findUser("123")
val name = user?.name ?: "Unknown" // Elvis operator
user?.let { println(it.name) } // Safe call with let

// When expression
fun getUserStatus(user: User): String = when {
    user.isActive && user.isPremium -> "Premium Active"
    user.isActive -> "Active"
    else -> "Inactive"
}

Coroutines and Flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

class UserRepository {
    private val api: UserApi

    // Suspend function
    suspend fun fetchUser(id: String): User {
        return withContext(Dispatchers.IO) {
            api.getUser(id)
        }
    }

    // Flow for reactive streams
    fun observeUsers(): Flow<List<User>> = flow {
        while (true) {
            val users = fetchUsers()
            emit(users)
            delay(5000) // Refresh every 5 seconds
        }
    }.flowOn(Dispatchers.IO)

    // StateFlow for state management
    private val _users = MutableStateFlow<List<User>>(emptyList())
    val users: StateFlow<List<User>> = _users.asStateFlow()

    suspend fun refreshUsers() {
        _users.value = fetchUsers()
    }
}

// Coroutine scopes
class UserViewModel : ViewModel() {
    private val repository = UserRepository()

    fun loadUsers() {
        viewModelScope.launch {
            try {
                val users = repository.fetchUser("123")
                // Update UI
            } catch (e: Exception) {
                // Handle error
            }
        }
    }

    // Parallel execution
    suspend fun loadMultipleUsers(ids: List<String>): List<User> {
        return coroutineScope {
            ids.map { id ->
                async { repository.fetchUser(id) }
            }.awaitAll()
        }
    }

    // Flow transformation
    fun searchUsers(query: String): Flow<List<User>> {
        return repository.observeUsers()
            .map { users -> users.filter { it.name.contains(query, ignoreCase = true) } }
            .distinctUntilChanged()
            .debounce(300)
    }
}

Android Jetpack Compose

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

@Composable
fun UserListScreen(viewModel: UserViewModel = viewModel()) {
    val users by viewModel.users.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()

    Scaffold(
        topBar = { TopAppBar(title = { Text("Users") }) }
    ) { padding ->
        if (isLoading) {
            CircularProgressIndicator(
                modifier = Modifier.fillMaxSize()
            )
        } else {
            LazyColumn(
                modifier = Modifier.padding(padding)
            ) {
                items(users) { user ->
                    UserCard(user = user)
                }
            }
        }
    }
}

@Composable
fun UserCard(user: User) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = user.name,
                style = MaterialTheme.typography.headlineSmall
            )
            Text(
                text = user.email,
                style = MaterialTheme.typography.bodyMedium
            )
        }
    }
}

Room Database

import androidx.room.*
import kotlinx.coroutines.flow.Flow

@Entity(tableName = "users")
data class UserEntity(
    @PrimaryKey val id: String,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "email") val email: String,
    @ColumnInfo(name = "created_at") val createdAt: Long
)

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

    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: String): UserEntity?

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: UserEntity)

    @Update
    suspend fun updateUser(user: UserEntity)

    @Delete
    suspend fun deleteUser(user: UserEntity)

    @Query("DELETE FROM users WHERE id = :userId")
    suspend fun deleteUserById(userId: String)
}

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

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

Dependency Injection with Hilt

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideUserApi(retrofit: Retrofit): UserApi {
        return retrofit.create(UserApi::class.java)
    }
}

@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @Inject lateinit var repository: UserRepository
}

Kotlin Multiplatform

// commonMain
expect class Platform() {
    val name: String
}

expect fun platformSpecificFunction(): String

// androidMain
actual class Platform actual constructor() {
    actual val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}

actual fun platformSpecificFunction(): String = "Android implementation"

// iosMain
actual class Platform actual constructor() {
    actual val name: String = UIDevice.currentDevice.systemName()
}

actual fun platformSpecificFunction(): String = "iOS implementation"

// Shared business logic
class UserService {
    suspend fun fetchUser(id: String): User {
        // Shared logic works on all platforms
        return api.getUser(id)
    }
}

Best Practices

Kotlin Style

  • Use val over var when possible
  • Leverage null safety features
  • Use data classes for DTOs
  • Prefer extension functions
  • Use sealed classes for type-safe states
  • Follow naming conventions

Coroutines

  • Use appropriate dispatchers (IO, Main, Default)
  • Handle cancellation properly
  • Avoid GlobalScope
  • Use structured concurrency
  • Prefer Flow over LiveData
  • Use StateFlow for state

Android

  • Follow MVVM architecture
  • Use Jetpack Compose for UI
  • Implement proper lifecycle handling
  • Use dependency injection
  • Handle configuration changes
  • Implement proper error handling

Anti-Patterns

❌ Using !! (non-null assertion) ❌ GlobalScope.launch ❌ Blocking main thread ❌ Not handling coroutine cancellation ❌ Tight coupling ❌ God classes ❌ Ignoring memory leaks

Resources

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View