
Everything You Need to Know About Your First Android Project
Welcome to Android development! This guide will walk you through every file and folder in a new Android project, explaining what each piece does, how they connect, and where to write your code. Let’s dive in!
📁 THE BIG PICTURE: Project Overview
MyAndroidApp/ ← Your project root
├── .gitignore ← Git ignore file
├── .gradle/ ← Gradle's internal cache (don't touch!)
├── .idea/ ← Android Studio settings (don't touch!)
├── .kotlin/ ← Kotlin compiler cache (don't touch!)
├── app/ ← YOUR MAIN CODE LIVES HERE! 🎯
├── build.gradle.kts ← Project-level build config
├── gradle/ ← Gradle wrapper + version catalog
├── gradle.properties ← Gradle settings
├── gradlew ← Gradle wrapper script (Mac/Linux)
├── gradlew.bat ← Gradle wrapper script (Windows)
├── local.properties ← Local machine config (don't commit!)
└── settings.gradle.kts ← Project settings & modules
Think of an Android project like a company:
- Root folder = The company headquarters
- app/ = The main product team
- gradle files = The operations/infrastructure team
- build/ folders = The factory output (generated stuff)
🏗️ PART 1: ROOT-LEVEL FILES (The Foundation)
1. settings.gradle.kts – The Project Registry
pluginManagement {
repositories {
google { ... } // Where Android libraries come from
mavenCentral() // Where most Java/Kotlin libraries come from
gradlePluginPortal() // Where Gradle plugins come from
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MyAndroidApp" // Your project name
include(":app") // Include the 'app' module
What it does:
- Tells Gradle “here are all my modules” (right now just
:app) - Defines WHERE to download libraries from (repositories)
- Sets the project name In real-world apps, you’ll have MULTIPLE modules:
include(":app")
include(":core:network")
include(":core:database")
include(":feature:login")
include(":feature:home")
This is called modularization and it’s crucial for large apps.
what is a module? a module is a self-contained, independent pice of your code that can be developed, tested and even compile separately/ It’s like has LEGO blocks- each block (module) has its own purpose, but they all connect together to build something bigger. In Android Studio, when you created your project, you already have one module — the app module. That’s your main application module. But as apps grow, you can add more modules.
Why Bother with Modularization? (The Real Benefits)
- faster build times changing something in a specific module only requires rebuilding that module instead of the whole app.
- team scalability At big companies (Meta, Google), different teams own different modules. The chat team doesn’t need to know how the calling team implemented their features.
- clear boundaries and ownership
this enforces architectire. A junior dev can’t accidentally create spaghetti dependencies - Code Reusability write once use everywher
2. build.gradle.kts (Root Level) – The Master Build Config
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
}
What are plugins?
Think of plugins like "Power-Ups" for your build system.
Gradle (your build system) by itself does'nt know how to:
Compile kotlin code
Build Android apks
handle jetpack compose
What it does:
- Declares plugins available to ALL modules
apply falsemeans “load but don’t activate here” (modules activate them individually)
Why alias(libs.plugins...)? This is the new Version Catalog system! Instead of writing versions everywhere, you define them once in gradle/libs.versions.toml.
3. gradle.properties – Gradle’s Settings
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
kotlin.code.style=official
android.nonTransitiveRClass=true
Line by line:
SettingWhat it meansorg.gradle.jvmargs=-Xmx2048mGive Gradle 2GB of RAM to work with
android.useAndroidX=trueUse modern AndroidX libraries (not old Support libraries)kotlin.code.style=officialUse JetBrains’ official Kotlin style
android.nonTransitiveRClass=trueEach module only sees its own resources (better for large projects)
When builds get slow, you can bump up the memory:
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
org.gradle.caching=true
4. gradle/libs.versions.toml – The Version Catalog (SUPER IMPORTANT!)
[versions]
agp = "8.11.2" # Android Gradle Plugin version
kotlin = "2.0.21" # Kotlin version
coreKtx = "1.17.0" # Core KTX library version
composeBom = "2024.09.00" # Compose Bill of Materials
[libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } # ... more libraries[plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"
Why this exists: Before version catalogs, you’d have versions scattered everywhere:
// OLD WAY - BAD! Versions everywhere!
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.compose.ui:ui:1.5.4")
Now you do:
// NEW WAY - GOOD! Single source of truth
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.ui)
The BOM (Bill of Materials) is MAGIC for Compose:
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui) // No version needed!
The BOM ensures all Compose libraries are compatible versions. Trust me, version conflicts are a NIGHTMARE.
5. gradlew and gradlew.bat – The Gradle Wrapper
These are scripts that download and run the correct Gradle version.
Why it matters:
- Your project says “I need Gradle 8.x”
- The wrapper automatically downloads it
- Everyone on the team uses the SAME Gradle version
- No “works on my machine” problems!
./gradlew build # On Mac/Linux
gradlew.bat build # On Windows
6. local.properties – Your Machine’s Secrets
sdk.dir=/Users/yourname/Library/Android/sdk
⚠️ NEVER COMMIT THIS FILE! It contains paths specific to YOUR computer.
📱 PART 2: THE APP MODULE (Where the Magic Happens!)
app/
├── build.gradle.kts ← App-specific build config
├── proguard-rules.pro ← Code obfuscation rules
├── src/
│ ├── main/ ← Your main code
│ │ ├── AndroidManifest.xml
│ │ ├── java/ ← Kotlin/Java code (yes, even Kotlin goes here!)
│ │ └── res/ ← Resources (images, strings, layouts)
│ ├── test/ ← Unit tests (run on JVM)
│ └── androidTest/ ← Instrumented tests (run on device/emulator)
└── build/ ← Generated files (don't touch!)
7. app/build.gradle.kts – The App’s Build Recipe
plugins {
alias(libs.plugins.android.application) // "This is an Android app"
alias(libs.plugins.kotlin.android) // "Using Kotlin"
alias(libs.plugins.kotlin.compose) // "Using Jetpack Compose"
}
android { namespace = "com.example.myapp" // Package name compileSdk = 36 // API level to compile against defaultConfig { applicationId = "com.example.myapp" // Unique ID on Play Store minSdk = 24 // Oldest Android supported (7.0 Nougat) targetSdk = 36 // Newest Android targeted versionCode = 1 // Internal version (must increase for updates) versionName = "1.0" // User-visible version } buildTypes { release { isMinifyEnabled = false // Should we shrink/obfuscate code? proguardFiles(...) // Rules for ProGuard } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = "11" } buildFeatures { compose = true // Enable Jetpack Compose! } }dependencies { // IMPLEMENTATION - Code you use, included in the app implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) // The BOM manages all Compose versions implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.material3) // TEST - Only for unit tests testImplementation(libs.junit) // ANDROID TEST - Only for instrumented tests androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) // DEBUG - Only in debug builds debugImplementation(libs.androidx.ui.tooling) }
Understanding SDK Versions:
┌─────────────────────────────────────────────────────────────┐
│ compileSdk = 36 │
│ (Use newest APIs for coding) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ targetSdk = 36 │ │
│ │ (App is optimized for this Android version) │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ minSdk = 24 │ │ │
│ │ │ (Oldest Android version your app runs on) │ │ │
│ │ │ Android 7.0 Nougat (2016) │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Understanding dependency types is CRUCIAL:
implementationNeeded at runtime, internalMost libraries
apiNeeded at runtime, exposed to other modulesShared models
compileOnlyOnly needed at compile timeAnnotations
testImplementationOnly for unit testsJUnit, Mockito
androidTestImplementationOnly for device testsEspresso
debugImplementationOnly in debug buildsLeakCanary
releaseImplementationOnly in release buildsCrash reporting
8. AndroidManifest.xml – The App’s ID Card
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApp">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Key Parts Explained:
<manifest>Root element, contains package info
<application>App-wide settings (icon, theme, backup)
<activity>Declares a screen in your app
android:exported="true"Can this component be launched by other apps?<intent-filter>Declares what “intents” this activity responds toaction.MAIN + category.LAUNCHER“This is the app’s entry point, show it in the launcher!”
The manifest is where you declare:
- Permissions:
<uses-permission android:name="android.permission.INTERNET" /> - Services: Background work
- Broadcast Receivers: Listen for system events
- Content Providers: Share data with other apps
📂 PART 3: JAVA/KOTLIN SOURCE CODE STRUCTURE
java/
└── com/
└── example/
└── myapp/ ← Your package (matches applicationId)
├── MainActivity.kt ← Entry point
└── ui/
└── theme/
├── Color.kt ← Color definitions
├── Theme.kt ← Theme configuration
├── Type.kt ← Typography
├── UI/
│ └── ui.kt ← Your UI components
└── viewmodel/
└── viewmodel.kt ← ViewModel
9. MainActivity.kt – The Entry Point
package com.example.myapp
import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import com.example.myapp.ui.theme.UI.Ui import com.example.myapp.ui.theme.viewmodel.CounterViewModelclass MainActivity : ComponentActivity() { val viewmodel = CounterViewModel() // Create the ViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() // Use the full screen setContent { // Set Compose UI as content Ui(viewmodel) } } }
What’s happening:
ComponentActivity– Base class for activities using ComposeonCreate()– Called when the activity is created (app launch)savedInstanceState– Android’s way of saving state during config changes (rotation)setContent { }– “Here’s my Compose UI!”
There’s a PROBLEM in this code!
val viewmodel = Counterviewmodel() // ❌ BAD! Gets destroyed on rotation!
The proper way:
val viewmodel: CounterViewModel by viewModels() // ✅ Survives rotation!
10. The UI Theme Files (Material Design System)
Color.kt – Your Color Palette
package com.example.myapp.ui.theme
import androidx.compose.ui.graphics.Colorval Purple80 = Color(0xFFD0BCFF) // Light theme primary val PurpleGrey80 = Color(0xFFCCC2DC) val Pink80 = Color(0xFFEFB8C8)val Purple40 = Color(0xFF6650a4) // Dark theme primary val PurpleGrey40 = Color(0xFF625b71) val Pink40 = Color(0xFF7D5260)
Why separate? Material Design has light AND dark themes. 80 suffix = light, 40 = dark.
Type.kt – Typography (Font Styles)
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
// titleLarge, labelSmall, etc.
)
What is sp? Scale-independent Pixels – like dp but respects user’s font size settings!
Theme.kt – Putting It All Together
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context)
else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
Dynamic Color = On Android 12+, colors can match user’s wallpaper!
11. Understanding ViewModel
package com.example.myapp.ui.theme.viewmodel
import androidx.lifecycle.ViewModelclass CounterViewModel: ViewModel() { val counter: Int = 7 }
What is a ViewModel?
- Holds UI data
- Survives configuration changes (screen rotation)
- Lives as long as the scope it’s attached to (Activity/Fragment)
┌─────────────────────────────────────────────────────────────┐
│ Activity Lifecycle │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Created │ ──► │ Rotated │ ──► │Destroyed │ │
│ │ │ │(recreate)│ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ViewModel (SURVIVES!) │ │
│ │ Created ─────────────────► Destroyed │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
12. The UI Composable
@Composable
fun Ui(vm: Counterviewmodel){
val count = vm.counter
var count1 by rememberSaveable { mutableStateOf(0) }
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center){
Column {
Text(text = "The count is $count")
Button(onClick = { count1 = clicking(count1) }) {
Text("Increase Count")
}
Text(text = "The count1 is $count1")
}
}
}
State in Compose:
TypeSurvives RecompositionSurvives Config Changeremember✅❌rememberSaveable✅✅ViewModel✅✅
📦 PART 4: RESOURCES FOLDER (res/)
res/
├── drawable/ ← Vector graphics, shapes
│ ├── ic_launcher_background.xml
│ └── ic_launcher_foreground.xml
├── mipmap-hdpi/ ← App icons (high density)
├── mipmap-mdpi/ ← App icons (medium density)
├── mipmap-xhdpi/ ← App icons (extra high)
├── mipmap-xxhdpi/ ← App icons (extra extra high)
├── mipmap-xxxhdpi/ ← App icons (extra extra extra high)
├── mipmap-anydpi-v26/ ← Adaptive icons (Android 8+)
├── values/
│ ├── colors.xml ← Color resources
│ ├── strings.xml ← Text strings
│ └── themes.xml ← XML themes
└── xml/
├── backup_rules.xml ← What to backup to cloud
└── data_extraction_rules.xml
Understanding Density Buckets
BucketDensityScaleExample Devicemdpi160 dpi1xBaselinehdpi240 dpi1.5xOld phonesxhdpi320 dpi2xMost phonesxxhdpi480 dpi3xHigh-end phonesxxxhdpi640 dpi4xFlagship phones
For app icons, always provide all densities. For other images, use vectors (SVG-like) when possible — they scale perfectly!
strings.xml – Never Hardcode Strings!
<resources>
<string name="app_name">MyApp</string>
</resources>
Why?
- Localization: Easy to translate
- Consistency: Change once, updates everywhere
- Play Store Requirement: For global apps
// ❌ BAD
Text("Hello World")
// ✅ GOOD
Text(stringResource(R.string.hello_world))
🔗 PART 5: HOW EVERYTHING CONNECTS
┌─────────────────────────────────────────────────────────────────────────┐
│ BUILD SYSTEM │
│ settings.gradle.kts → "Include :app module" │
│ │ │
│ ▼ │
│ build.gradle.kts (root) → "Here are available plugins" │
│ │ │
│ ▼ │
│ libs.versions.toml → "Here are all library versions" │
│ │ │
│ ▼ │
│ app/build.gradle.kts → "I'm an Android app using these dependencies" │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ RUNTIME │
│ AndroidManifest.xml → "MainActivity is the entry point" │
│ │ │
│ ▼ │
│ MainActivity.kt → onCreate() → setContent { Ui(viewmodel) } │
│ │ │
│ ▼ │
│ Theme.kt → MaterialTheme wraps your content │
│ │ │
│ ▼ │
│ ui.kt → Your actual UI composables │
│ │ │
│ ▼ │
│ viewmodel.kt → Holds your data/state │
└─────────────────────────────────────────────────────────────────────────┘
🏢 PART 6: RECOMMENDED PROJECT STRUCTURE (Real World)
app/src/main/java/com/yourcompany/app/
├── MainActivity.kt
├── MyApplication.kt ← Application class for initialization
│
├── data/ ← DATA LAYER
│ ├── local/ ← Local database
│ │ ├── AppDatabase.kt
│ │ ├── dao/
│ │ │ └── UserDao.kt
│ │ └── entity/
│ │ └── UserEntity.kt
│ ├── remote/ ← Network/API
│ │ ├── ApiService.kt
│ │ └── dto/
│ │ └── UserDto.kt
│ └── repository/ ← Data sources combination
│ └── UserRepository.kt
│
├── domain/ ← DOMAIN LAYER (Business Logic)
│ ├── model/
│ │ └── User.kt ← Clean domain models
│ └── usecase/
│ └── GetUserUseCase.kt
│
├── presentation/ ← PRESENTATION LAYER (UI)
│ ├── navigation/
│ │ └── NavGraph.kt
│ ├── common/
│ │ └── components/ ← Reusable UI components
│ │ └── LoadingSpinner.kt
│ └── feature/
│ ├── home/
│ │ ├── HomeScreen.kt
│ │ └── HomeViewModel.kt
│ └── profile/
│ ├── ProfileScreen.kt
│ └── ProfileViewModel.kt
│
├── di/ ← Dependency Injection
│ └── AppModule.kt
│
└── util/ ← Utilities
└── Extensions.kt
💡 PART 7: WHICH FILE FOR WHAT? (Decision Guide)
- Add a new screenCreate in
presentation/feature/ - Add a new network call
data/remote/ApiService.kt - Save data locally
data/local/with Room database - Add a reusable button
presentation/common/components/ - Add app-wide colors
ui/theme/Color.kt - Add a new string
res/values/strings.xml - Add an image
res/drawable/(vector) orres/mipmap-*/ - Request a permission
AndroidManifest.xml - Change app icon
res/mipmap-*/folders - Add a new library
app/build.gradle.ktsin dependencies - Add a background service
- Create Service class + register in Manifest
🚨 PART 8: BEST PRACTICES & GOLDEN RULES
1. Never Touch build/ Folders
Everything in there is generated. Delete it if builds break (or run ./gradlew clean).
2. Always Use Version Catalogs
Keep all versions in libs.versions.toml. Your future self will thank you.
3. Commit .gitignore Properly
# These should be ignored:
*.iml
.gradle/
/local.properties
/.idea/
/build/
/app/build/
4. Understand the Build Variants
buildTypes {
debug { } // For development
release { } // For production
}
productFlavors {
dev { } // Dev environment
staging { } // Test environment
prod { } // Production
}
// Results in: devDebug, devRelease, stagingDebug, stagingRelease, prodDebug, prodRelease
5. Resources are Magic
Android automatically picks the right resource:
values/→ Defaultvalues-es/→ Spanishvalues-night/→ Dark modedrawable-xxhdpi/→ High DPI screens
6. The R Class is Your Friend
Android generates R.java with references to all resources:
R.string.app_name // String resource
R.drawable.icon // Image resource
R.color.primary // Color resource
R.id.button_submit // View ID
🎓 QUICK REFERENCE CARD
┌────────────────────────────────────────────────────────────────┐
│ ANDROID PROJECT CHEAT SHEET │
├────────────────────────────────────────────────────────────────┤
│ BUILD SYSTEM │
│ settings.gradle.kts → Module registration │
│ build.gradle.kts → Plugins & dependencies │
│ gradle.properties → Gradle settings │
│ libs.versions.toml → Version management │
├────────────────────────────────────────────────────────────────┤
│ APP CONFIGURATION │
│ AndroidManifest.xml → App identity & components │
│ proguard-rules.pro → Code obfuscation rules │
├────────────────────────────────────────────────────────────────┤
│ SOURCE CODE (java/) │
│ *Activity.kt → Screen/Entry points │
│ *ViewModel.kt → UI state holders │
│ *Screen.kt → Composable screens │
│ *Repository.kt → Data sources │
├────────────────────────────────────────────────────────────────┤
│ RESOURCES (res/) │
│ drawable/ → Vector graphics │
│ mipmap-*/ → App icons │
│ values/strings.xml → Text strings │
│ values/colors.xml → Color definitions │
│ values/themes.xml → XML themes │
│ xml/ → Configuration files │
└────────────────────────────────────────────────────────────────┘
Job Offers
🎯 YOUR NEXT STEPS
- Run the app — See it working!
- Modify strings.xml — Change the app name
- Add a new color — Use it in your composable
- Create a new screen — Practice the pattern
- Add a dependency — Try adding a new library
Welcome to Android development! It’s a deep field with lots to learn, but let’s take it step by step.
This article was previously published on proandroiddev.com



