Kotlin Android development combines the Kotlin programming language with Android’s application framework, Jetpack libraries, and development tools. This tutorial explains how to set up Android Studio, create a Kotlin project, build a basic interface with Jetpack Compose, manage state, run the application, and plan the next stages of Android development.

Kotlin is a statically typed language with null-safety, type inference, coroutines, extension functions, data classes, and Java interoperability. Android development is Kotlin-first, while existing Java code and Java libraries can continue to be used in Kotlin projects. Refer to the official Android Kotlin documentation and Kotlin for Android overview when checking current tooling and API guidance.

Kotlin Android Development Learning Path

  1. Learn Kotlin variables, functions, classes, null-safety, collections, lambdas, and coroutines.
  2. Install Android Studio and create a Kotlin Android project.
  3. Understand activities, application resources, manifests, and the Android lifecycle.
  4. Build screens with Jetpack Compose or maintain XML-based Android Views where required.
  5. Manage screen state with state holders and ViewModel.
  6. Navigate between screens and pass identifiers rather than large objects.
  7. Load data with coroutines and expose observable UI state.
  8. Store local data and communicate with remote services.
  9. Write unit, UI, and integration tests.
  10. Build, sign, inspect, and release the application.

Install Kotlin Android Tools in Android Studio

Android Studio includes the tools needed to create Kotlin Android applications. A separate Kotlin download is normally unnecessary for an Android Studio project because the project build configuration declares the Kotlin and Android plugins it needs.

  1. Download a stable Android Studio release from the official Android Developers website.
  2. Complete the setup wizard and install the recommended Android SDK components.
  3. Open the SDK Manager and confirm that the Android SDK platform required by the project is installed.
  4. Create an Android Virtual Device, or connect a physical Android device with developer options and USB debugging enabled.
  5. Allow Android Studio to complete the initial Gradle synchronization before editing the generated project.

Use the Android Studio version, Android Gradle Plugin version, Kotlin version, and Java toolchain recommended for the same project template. Copying unrelated version numbers from different tutorials can create plugin or compiler compatibility errors.

Create a Kotlin Android Project

  1. Select New Project in Android Studio.
  2. Choose an empty activity template that uses Jetpack Compose.
  3. Enter an application name such as Kotlin Android Example.
  4. Set a unique package name, for example com.example.kotlinandroid.
  5. Select Kotlin when the template provides a language choice.
  6. Choose the minimum Android SDK according to the devices and platform features the application must support.
  7. Create the project and wait for Gradle synchronization and indexing to finish.

The generated project contains a working activity, theme, Gradle configuration, application resources, and manifest. Run this unmodified project first. A successful initial run separates environment problems from errors introduced by later code changes.

Kotlin Android Project Structure

Project locationPurpose in a Kotlin Android app
app/src/main/java or app/src/main/kotlinKotlin source files, including activities, composables, ViewModels, repositories, and data models
app/src/main/resStrings, icons, colors, XML layouts, and other Android resources
AndroidManifest.xmlApplication components, permissions, intent filters, and application metadata
app/build.gradle.ktsModule plugins, Android configuration, build types, and dependencies
app/src/testLocal unit tests that normally run on the development machine
app/src/androidTestInstrumented and UI tests that run on an Android device or emulator

Kotlin Syntax Used in Android Applications

Kotlin uses val for a read-only reference and var for a reference that can be reassigned. Type inference allows the compiler to determine many variable types without an explicit declaration.

</>
Copy
val appName = "Kotlin Android Example"
var launchCount = 0

fun welcomeMessage(userName: String): String {
    return "Welcome, $userName"
}

Kotlin Null-Safety in Android Code

A non-nullable variable cannot normally contain null. Add ? when absence is a valid state, and handle that state explicitly with safe calls or another control-flow mechanism.

</>
Copy
var displayName: String? = null

val visibleName = displayName?.trim()?.takeIf { it.isNotEmpty() }
    ?: "Guest"

Avoid using !! merely to silence a nullability error. It throws an exception when the value is null and removes the protection that Kotlin’s type system provides.

Kotlin Data Classes for Android UI State

A data class is suitable for representing immutable screen state or data transferred between application layers.

</>
Copy
data class ProfileUiState(
    val name: String = "",
    val isLoading: Boolean = false,
    val errorMessage: String? = null
)

Build a First Kotlin Android App with Jetpack Compose

Jetpack Compose defines the interface through Kotlin functions marked with @Composable. The following activity displays a greeting and a button. It uses the Material theme generated by the project template.

</>
Copy
package com.example.kotlinandroid

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MaterialTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    WelcomeScreen(name = "Android Developer")
                }
            }
        }
    }
}

@Composable
fun WelcomeScreen(name: String) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(24.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Hello, $name",
            style = MaterialTheme.typography.headlineSmall
        )

        Button(
            onClick = { /* Handle the user action */ },
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text(text = "Continue")
        }
    }
}

Replace the package declaration with the package used by your project. Android Studio can add missing imports automatically. The theme wrapper may have a project-specific name if the template generated a custom theme function.

Manage State in a Kotlin Android Compose Screen

A Compose interface is redrawn when observed state changes. Use rememberSaveable for small UI values that should survive activity recreation and can be stored in a bundle-compatible form.

</>
Copy
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun CounterScreen() {
    var count by rememberSaveable { mutableIntStateOf(0) }

    Column(modifier = Modifier.padding(24.dp)) {
        Text(text = "Count: $count")

        Button(
            onClick = { count++ },
            modifier = Modifier.padding(top = 12.dp)
        ) {
            Text(text = "Increase")
        }
    }
}

Do not place long-running work, database operations, or network requests directly inside a composable. Keep business state in a ViewModel or another state holder and pass state and event callbacks into the UI.

Kotlin Android ViewModel and Unidirectional UI State

A ViewModel retains screen-related state across configuration changes. A common design sends user events from the UI to the ViewModel and exposes immutable state back to the UI.

</>
Copy
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update

data class CounterUiState(val count: Int = 0)

class CounterViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(CounterUiState())
    val uiState: StateFlow<CounterUiState> = _uiState.asStateFlow()

    fun increaseCount() {
        _uiState.update { currentState ->
            currentState.copy(count = currentState.count + 1)
        }
    }
}

In Compose, collect lifecycle-aware state using the Android lifecycle integration available in the project. This prevents unnecessary collection while the interface is not in an active lifecycle state.

Kotlin Coroutines for Android Background Work

Coroutines allow asynchronous work to be expressed in sequential-looking Kotlin code. A suspending function can pause without blocking the underlying thread. Android applications commonly launch screen-related work in viewModelScope, which is cancelled when the ViewModel is cleared.

</>
Copy
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class ProfileViewModel(
    private val repository: ProfileRepository
) : ViewModel() {
    private val _uiState = MutableStateFlow(ProfileUiState())
    val uiState = _uiState.asStateFlow()

    fun loadProfile() {
        viewModelScope.launch {
            _uiState.value = ProfileUiState(isLoading = true)

            _uiState.value = try {
                val profile = repository.loadProfile()
                ProfileUiState(name = profile.name)
            } catch (exception: Exception) {
                ProfileUiState(errorMessage = "Unable to load profile")
            }
        }
    }
}

The repository decides whether data comes from a network service, database, cache, or another source. Production code should distinguish expected failures, preserve useful diagnostics, and avoid presenting sensitive exception details directly to users.

Kotlin Android Activities and Lifecycle Handling

An activity is an Android component that commonly provides a window for a screen. Important lifecycle callbacks include onCreate(), onStart(), onResume(), onPause(), onStop(), and onDestroy(). The system can recreate an activity after configuration changes or process restoration.

  • Initialize the activity and Compose content in onCreate().
  • Keep durable application data outside the activity.
  • Use ViewModel for screen state that should survive configuration changes.
  • Use saved-state mechanisms for small values needed after system-initiated recreation.
  • Register and unregister resource-sensitive listeners with lifecycle-aware APIs.
  • Do not assume onDestroy() always runs before the application process ends.

Jetpack Compose and XML Views in Kotlin Android Apps

Jetpack Compose is the modern Kotlin-based toolkit for Android interfaces. XML layouts and Android Views remain relevant in existing applications, third-party integrations, and gradual migrations. Kotlin can be used with either approach.

UI approachHow the interface is definedCommon project context
Jetpack ComposeKotlin composable functionsNew screens and applications using declarative state-driven UI
Android ViewsXML layouts and View objectsExisting applications, legacy components, or View-based libraries
InteroperabilityCompose and Views hosted within one applicationIncremental migration or components that require a different UI system

Kotlin Android Navigation and Screen Arguments

Android navigation should define clear destinations and a predictable back stack. Pass small identifiers, such as an item ID, and load the current record from a repository. Passing large mutable objects between screens can produce stale state and exceed Android transaction limits.

  • Define stable destination routes or typed destinations supported by the navigation setup.
  • Validate every argument received from a route, deep link, or external intent.
  • Keep navigation commands separate from reusable screen content where practical.
  • Test system Back behavior, app-bar Up behavior, deep links, and process recreation.
  • Do not place secrets or sensitive personal data in route strings.

Kotlin Android Permissions and Manifest Configuration

The Android manifest declares application components and permissions. Some permissions are granted during installation, while sensitive permissions may also require a runtime request. Request a permission only when the user starts a feature that needs it, explain the feature-specific reason, and handle denial without crashing.

</>
Copy
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:label="@string/app_name"
        android:theme="@style/Theme.KotlinAndroid">
        <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>

The generated theme name may differ from the example. Components with intent filters require an explicit exported setting on applicable Android versions. Review every exported component because it can be invoked from outside the application.

Run and Debug a Kotlin Android Application

  1. Select the application run configuration in Android Studio.
  2. Choose an emulator or connected Android device.
  3. Select Run and wait for the application to install.
  4. Open Logcat to inspect application logs and exception stack traces.
  5. Set a breakpoint and use the debugger when values or execution flow are unclear.
  6. Use the Layout Inspector for interface hierarchy and rendering investigations.
  7. Use Android profiling tools only after reproducing a measurable CPU, memory, network, or energy issue.

If the build fails, read the first relevant error rather than only the final Gradle summary. Confirm plugin compatibility, SDK installation, Java toolchain configuration, dependency resolution, and the file and line named in the compiler output.

Kotlin Android Application Architecture

A maintainable Android application separates interface code, state management, business rules, and data access. The exact number of layers should match the application’s size rather than following a rigid folder structure.

  • UI layer: Displays immutable state and sends user events.
  • State holder or ViewModel: Coordinates screen logic and exposes observable UI state.
  • Domain logic: Contains reusable business rules when the application needs a distinct domain layer.
  • Repository: Provides a stable data interface and coordinates local or remote sources.
  • Data source: Communicates with databases, files, platform services, or network APIs.

Prefer unidirectional data flow: state moves toward the UI, while user events move toward the state holder. This makes screen behavior easier to test and reduces conflicting sources of truth.

Test Kotlin Android Code

  • Write local unit tests for Kotlin functions, state transformations, and business rules.
  • Use test doubles for repositories or data sources when testing a ViewModel.
  • Write Compose UI tests for visible content and user interactions.
  • Use instrumented tests for behavior that depends on Android framework APIs or a device.
  • Test loading, empty, success, validation, offline, permission-denied, and failure states.
  • Check screen restoration, rotation, backgrounding, and process recreation for state-sensitive features.

Kotlin Android Tutorial Editorial QA Checklist

  • Verify that every Kotlin code sample compiles with the Android Studio project configuration described by the tutorial.
  • Confirm that Compose, Android View, activity, and ViewModel terminology is not mixed incorrectly.
  • Check that all Compose state examples explain whether values survive recomposition, activity recreation, or process death.
  • Confirm that coroutine examples use a lifecycle-appropriate scope and do not perform blocking work on the main thread.
  • Verify that nullable values are handled safely without unnecessary !! operators.
  • Check manifest examples for exported-component and permission implications.
  • Confirm that no API key, signing credential, token, or other secret appears in source-code examples.
  • Test the sample on both an emulator and a physical device when hardware or permission behavior is discussed.
  • Review version-sensitive Gradle, Kotlin, Compose, and Android SDK instructions against current official documentation.
  • Ensure that accessibility labels, readable contrast, scalable text, and touch-target behavior are considered in UI examples.

Kotlin Android Development FAQs

Is Kotlin used for Android development?

Yes. Kotlin is supported for Android application development and is used with Android framework APIs, Jetpack libraries, Jetpack Compose, and existing Java libraries. New and existing Android projects can contain both Kotlin and Java source files.

Is Java or Kotlin better for Android development?

Kotlin is generally the practical starting point for a new Android project because current Android guidance, Compose APIs, and many learning resources are Kotlin-focused. Java remains relevant for maintaining existing applications and libraries. Kotlin’s Java interoperability allows teams to migrate incrementally instead of rewriting an application at once.

Is Kotlin free to use for Android apps?

Yes. Kotlin is open-source and can be used without purchasing a language licence. Android Studio is also available for Android application development. Teams should still review the licences of third-party libraries and services added to their applications.

Do I need to install a separate Kotlin Android plugin?

Android Studio includes Kotlin support. A Kotlin Android project declares the required Kotlin and Android build plugins through its Gradle configuration. Use the versions generated or recommended by the current Android Studio project template rather than installing unrelated compiler files manually.

How should a beginner learn Kotlin Android development?

Begin with Kotlin syntax and null-safety, then create a small Android Studio project. Build one screen, manage its state, add navigation, load data through a repository, and write tests. Expand the same project gradually so that lifecycle, asynchronous work, storage, permissions, and architecture are learned in context. The Kotlin language website provides language documentation, while the Android Developers site documents Android-specific APIs and practices.