Skip to content

Android Studio — Complete Guide for Beginners

DodaTech Updated 2026-06-20 12 min read

In this tutorial, you'll learn about Android Studio. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Android Studio is the official IDE for Android apps with a Gradle build system, visual layout editor, emulator, and profiling tools in one package.

In this tutorial, you will learn how to install Android Studio, create your first Android project with Kotlin and Jetpack Compose, configure the emulator, use the debugger and Logcat, manage dependencies with Gradle, run performance tests with the Profiler, and prepare your app for Google Play Store submission. These are the same workflows DodaTech uses to build mobile versions of Doda Browser and Durga Antivirus Pro for Android — mastering Android Studio gives you complete control over the full app lifecycle. We'll draw parallels with Python and JavaScript ecosystems throughout.

What You'll Learn

By the end of this guide, you will know how to create an Android project from scratch, design UIs with Jetpack Compose, run and debug apps on the emulator and physical devices, inspect network traffic and memory usage with the Profiler, and generate a signed APK or App Bundle for distribution.

Why Android Studio Matters

Android powers over 70% of mobile devices worldwide. Android Studio is the only officially supported IDE for the platform, and it provides deep integration with the Android SDK, build tools, and Google services. Its Gradle build system handles dependency management, multi-module projects, and variant-specific configurations (debug, release, staging). The Layout Inspector and Profiler help you diagnose UI jank and memory leaks before they reach users. For security tools like Durga Antivirus Pro, the Profiler is critical for ensuring background scanning services do not drain battery or consume excessive memory.

Learning Path

flowchart LR
  A[Installation & SDK Setup] --> B[First Project with Jetpack Compose]
  B --> C[Emulator & Device Testing]
  C --> D[Debugging & Logcat]
  D --> E{You Are Here}
  E --> F[Profiler & Performance]
  E --> G[Play Store Deployment]
  style E fill:#f90,color:#fff

Installation and SDK Setup

Download Android Studio from developer.android.com/studio. The installer includes the Android SDK, emulator, and build tools. During installation, choose Standard setup — it installs the latest SDK for the most common API levels.

SDK Manager

Open Tools → SDK Manager. Here you manage API levels, build tools, and system images:

Component Purpose Recommended Version
Android SDK Platform API level for compilation Latest stable (API 35)
Intel x86 Atom System Image Emulator image API 35 with Google Play
Android SDK Build-Tools APK signing and packaging Latest
Android Emulator Virtual device testing Latest
Android SDK Platform-Tools ADB and fastboot Latest

Ensure Android_HOME is set in your environment variables:

# Add to ~/.zshrc or ~/.bashrc
export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/tools/bin

Creating Your First Android Project

Click File → New → New Project. Choose Empty Views Activity (Jetpack Compose):

Setting Recommended Value Purpose
Name MyFirstApp App display name
Package name com.example.myfirstapp Unique identifier for Play Store
Save location ~/AndroidStudioProjects Project root
Language Kotlin Modern, concise, Google-preferred
Minimum SDK API 24 (Android 7.0) Covers 95%+ of active devices

Android Studio generates the project with MainActivity.kt, activity_main.xml (or Composable functions for Compose), and build.gradle.kts files.

Project Structure

File/Directory Purpose
app/src/main/java/ Kotlin source code
app/src/main/res/ Resources: layouts, drawables, strings
app/build.gradle.kts Module-level build configuration
build.gradle.kts Project-level build configuration
settings.gradle.kts Module inclusion and Repository config
gradle.properties JVM args and project-wide Gradle settings

Building User Interfaces with Jetpack Compose

Jetpack Compose is Android's modern declarative UI toolkit. You describe your UI in Kotlin functions annotated with @Composable.

// MainActivity.kt — Hello World with Compose
package com.example.myfirstapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
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 {
                Greeting("Android Studio")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    var count by remember { mutableStateOf(0) }

    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "Hello, $name!",
            style = MaterialTheme.typography.headlineLarge
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text("Button pressed $count times")
        Spacer(modifier = Modifier.height(8.dp))
        Button(onClick = { count++ }) {
            Text("Tap me")
        }
    }
}
Expected output on emulator:
  - Centered "Hello, Android Studio!" in large text
  - "Button pressed 0 times"
  - Tapping the button increments the counter
  - Material 3 theming with default colors and rounded corners

Preview in Android Studio

Add the @Preview annotation above Greeting to see a live preview panel:

@Preview(showBackground = true, showSystemUi = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting("Android Studio")
    }
}

The preview panel updates as you type — no emulator needed for basic layout work.

Running on the Emulator

Open Tools → Device Manager and click Create Device. Select a hardware profile (Pixel 8 is a good default) and a system image (API 35). Click Finish.

Emulator Shortcuts

Shortcut Action
Ctrl+F11 Rotate device
Ctrl+Shift+A Extended controls (location, battery, phone)
Ctrl+F6 Take screenshot
Triple-finger swipe Quick settings / notifications

Run your app with Shift+F10. Android Studio installs the APK on the emulator and launches the activity. The Run tool window shows log output:

$ adb install -t -r app/build/outputs/apk/debug/app-debug.apk
Success
$ adb shell am start -n "com.example.myfirstapp/.MainActivity"
Starting: Intent { cmp=com.example.myfirstapp/.MainActivity }

Debugging with Logcat

The Logcat tool window (Alt+6) displays all device log messages. Filter by package name or log level:

Log Level Method Use Case
V Log.v() Verbose — detailed debugging
D Log.d() Debug — development diagnostics
I Log.i() Info — general operational messages
W Log.w() Warning — potential issues
E Log.e() Error — failures requiring attention
WTF Log.wtf() What a Terrible Failure — should-never-happen bugs
// LoggingDemo.kt — demonstrate Logcat levels
import android.util.Log
import androidx.compose.runtime.Composable

private const val TAG = "MainActivity"

@Composable
fun LoggingExample() {
    Log.v(TAG, "Verbose: entering composable")
    Log.d(TAG, "Debug: initializing state")
    Log.i(TAG, "Info: user opened the app")
    // Simulate a recoverable error
    try {
        val result = riskyOperation()
        Log.d(TAG, "Operation result: $result")
    } catch (e: Exception) {
        Log.e(TAG, "Error in riskyOperation", e)
    }
}

fun riskyOperation(): String {
    Log.w(TAG, "Warning: riskyOperation may fail on null input")
    return "success"
}
Logcat output (filtered by 'MainActivity'):
D/MainActivity: Debug: initializing state
I/MainActivity: Info: user opened the app
W/MainActivity: Warning: riskyOperation may fail on null input
D/MainActivity: Operation result: success

Breakpoints and Variable Inspection

Set breakpoints by clicking the gutter in the Kotlin editor. Run the app in debug mode (Shift+F9). When execution pauses, hover over variables to inspect their values, or use the Variables pane to navigate the call stack.

Gradle Build System

Gradle is Android's build system. Every Android project has two build.gradle.kts files.

Project-Level build.gradle.kts

// build.gradle.kts (Project: MyFirstApp)
plugins {
    id("com.android.application") version "8.5.0" apply false
    id("org.jetbrains.kotlin.android") version "2.0.0" apply false
}

Module-Level build.gradle.kts

// app/build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.example.myfirstapp"
    compileSdk = 35

    defaultConfig {
        applicationId = "com.example.myfirstapp"
        minSdk = 24
        targetSdk = 35
        versionCode = 1
        versionName = "1.0.0"
    }

    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
}

dependencies {
    implementation("androidx.core:core-ktx:1.13.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0")
    implementation("androidx.activity:activity-compose:1.9.0")
    implementation(platform("androidx.compose:compose-bom:2024.05.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    debugImplementation("androidx.compose.ui:ui-tooling")
}

Common Gradle Tasks

Run these from the Gradle tool window (right sidebar) or terminal. Git commands are also available via the built-in terminal:

./gradlew assembleDebug          # Build debug APK
./gradlew assembleRelease        # Build release APK (signed)
./gradlew lint                   # Run lint checks
./gradlew test                   # Run unit tests
./gradlew connectedAndroidTest   # Run instrumented tests on device

Common Errors

1. "Failed to find Build Tools revision"

The project specifies a build tools version not installed in your SDK.

Fix: Open SDK Manager → SDK Tools, check "Show Package Details", and install the missing build tools version. Or update build.gradle.kts to use an installed version.

2. Emulator "KVM is not installed" on Linux

The emulator requires KVM for hardware acceleration.

Fix:

sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils
sudo adduser $USER kvm

Log out and back in, then restart the emulator.

3. "INSTALL_FAILED_UPDATE_INCOMPATIBLE" When Installing on Device

An existing app with the same package name but a different signature is installed.

Fix: Uninstall the existing app:

adb uninstall com.example.myfirstapp

Then reinstall.

4. Gradle Sync Failing with "Could not resolve" Dependency

A required library cannot be downloaded.

Fix: Check your internet connection. Add mavenCentral() or google() to the repositories block in settings.gradle.kts if missing. Use File → Invalidate Caches and Restart to clear the Gradle cache.

// settings.gradle.kts
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

5. App Crashing with "Cannot access 'fragment' on stopped activity"

The activity was destroyed (orientation change, memory reclaim) but a background Coroutine called a reference.

Fix: Use lifecycleScope.launch with Lifecycle.repeatOnLifecycle pattern, and never hold a Context reference longer than the lifecycle owner. The fix in Durga Antivirus Pro's background scanner uses a bounded service with a lifecycle-aware coroutine scope.

// Safe lifecycle-aware coroutine
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        // Safe to access UI here
        viewModel.uiState.collect { state ->
            updateUI(state)
        }
    }
}

6. R8/ProGuard Removes Required Classes in Release Build

Release builds crash with ClassNotFoundException because ProGuard stripped reflection-accessed classes.

Fix: Add keep rules in proguard-rules.pro:

-keep class com.example.myfirstapp.** { *; }
-keepattributes *Annotation*
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

7. Layout Inspector Shows "Not connected"

The Layout Inspector cannot connect to the running app.

Fix: Ensure the app is compiled with debuggable = true. Use the debug build variant. If using a physical device, enable USB debugging in Developer Options and authorize the computer.

FAQ

What is the difference between an APK and an App Bundle?

APK (Android Package Kit) is the traditional distribution format. AAB (Android App Bundle) is the modern format required by Google Play since August 2021. AAB defers APK generation to Google Play, which creates optimized APKs per device configuration (screen density, CPU architecture, language), reducing download size by up to 35%.

Do I need a physical Android device for development?

No — the Android Emulator handles most development scenarios. However, testing on physical devices catches real-world issues: battery drain, network speed, camera behavior, and sensor accuracy. DodaTech tests Durga Antivirus Pro on 10+ physical devices before each release.

How do I update the Android SDK after installing Android Studio?

Open Tools → SDK Manager. The SDK Platforms tab lists available API levels; check new ones and click Apply. SDK Tools includes updates to the emulator, build tools, and platform-tools. Android Studio also prompts you when a new SDK revision is available.

Practice Questions

1. What is the difference between compileSdk, minSdk, and targetSdk in Gradle?

compileSdk is the API level used to compile your app. minSdk is the lowest API level your app supports. targetSdk signifies you have tested your app on this API level — Android uses this for backward compatibility behavior changes.

2. How do you add a button click event in Jetpack Compose?

Use Button(onClick = { /* handler */ }) { Text("Click") }. The onClick lambda runs when the user taps the button.

3. What Logcat level should you use for debugging during development?

Use Log.d() (Debug) for development diagnostics. Use Log.v() for high-frequency verbose logging that should be disabled in production. Use Log.e() for errors only.

4. How do you install an APK on a physical device using the command line?

Connect the device via USB, enable USB debugging, then run adb install app-debug.apk. Use adb devices first to verify the device is listed.

5. Challenge: Build a note-taking app with Compose

Create a new Android project. Build a Note data class with id: Int, title: String, content: String, and timestamp: Long. Display notes in a LazyColumn. Add a FAB (Floating Action Button) that opens a dialog to add a new note. Use remember and mutableStateListOf for state management without ViewModel. Run on the emulator and verify notes persist across orientation changes.

Mini Project: Network Request with Retrofit and JSON Parsing

Add a network layer to your app using Retrofit.

app/build.gradle.kts — add dependencies:

dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}

ApiService.kt — define the API interface:

package com.example.myfirstapp

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

data class Todo(val id: Int, val title: String, val completed: Boolean)

interface ApiService {
    @GET("todos")
    suspend fun getTodos(): List<Todo>
}

object RetrofitClient {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"

    val instance: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

NetworkViewModel.kt — manage UI state:

package com.example.myfirstapp

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class NetworkViewModel : ViewModel() {
    private val _todos = MutableStateFlow<List<Todo>>(emptyList())
    val todos: StateFlow<List<Todo>> = _todos

    init { fetchTodos() }

    private fun fetchTodos() {
        viewModelScope.launch {
            try {
                _todos.value = RetrofitClient.instance.getTodos()
            } catch (e: Exception) {
                // Handle error — this pattern is used in Doda Browser's
                // network resilience layer for retry and fallback
            }
        }
    }
}

Set breakpoints in fetchTodos() and step through the network call. Use Logcat with filter Retrofit to see HTTP request/response logs from OkHttp's logging interceptor.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro