Introduction
The Android Software Development Kit (SDK) is a comprehensive collection of tools, libraries, and APIs that developers use to create applications for the Android platform. This cheatsheet provides a comprehensive overview of the Android SDK components, essential tools, key APIs, and best practices. Understanding these elements is crucial for efficient Android app development, debugging, and optimization. Whether you’re starting your first Android project or looking to deepen your knowledge of specific SDK features, this guide will serve as a valuable reference.
Android SDK Components Overview
SDK Manager Core Components
Component | Description | Key Features |
---|
SDK Tools | Essential development tools | ADB, DDMS, AVD Manager, Lint |
SDK Platform-Tools | Interface with Android devices | ADB, Fastboot, Systrace |
SDK Platform | Android API libraries and system images | API level-specific libraries, system images |
SDK Build-Tools | Compile and package Android apps | dx, aapt, dexdump, zipalign |
Emulator | Virtual device for testing | Hardware acceleration, snapshots, multi-display support |
System Images | OS images for emulator | x86/ARM architectures, Google APIs, Google Play |
Sources | Android platform source code | Reference material for platform behavior |
Extras | Additional libraries and tools | Support library, Play services, constraint layout |
SDK Directory Structure
android-sdk/
├── build-tools/ # Version-specific build tools
├── emulator/ # Android emulator files
├── licenses/ # SDK license agreements
├── patcher/ # Dependency patch files
├── platform-tools/ # ADB and other device tools
├── platforms/ # API-specific Android platforms
├── sources/ # Android source code
├── system-images/ # Emulator system images
├── tools/ # Core development tools
└── extras/ # Additional libraries
Essential Android SDK Tools
Android Debug Bridge (ADB)
# Device Management
adb devices # List connected devices
adb -s <device-id> <command> # Send command to specific device
adb connect <ip>:<port> # Connect to device over network
adb disconnect # Disconnect all network devices
# App Installation and Management
adb install -r app.apk # Install/replace application
adb uninstall com.example.app # Uninstall application
adb shell pm list packages # List installed packages
adb shell am start -n com.package.name/.ActivityName # Launch activity
# File Transfer
adb push <local> <remote> # Copy file/dir to device
adb pull <remote> <local> # Copy file/dir from device
# Logging
adb logcat # View device logs
adb logcat -v threadtime # Detailed logs with timestamps
adb logcat "*:E" # Show only errors
adb logcat -c # Clear log buffer
# Debugging
adb shell dumpsys # Dump system information
adb shell dumpsys meminfo # Memory usage info
adb shell dumpsys activity # Activity manager state
adb shell dumpsys battery # Battery status
adb shell screencap -p /sdcard/screen.png # Take screenshot
adb shell screenrecord /sdcard/video.mp4 # Record screen
Emulator
# Starting emulator from command line
emulator -avd <avd_name> # Start specific AVD
emulator -avd <avd_name> -wipe-data # Factory reset emulator
emulator -list-avds # List available AVDs
emulator -avd <name> -camera-back webcam0 # Use webcam as camera
# Advanced emulator options
emulator -avd <name> -no-snapshot-load # Start without snapshot
emulator -avd <name> -gpu host # Use host GPU
emulator -avd <name> -netdelay umts # Simulate network delay
emulator -avd <name> -netspeed gsm # Simulate network speed
emulator -avd <name> -dns-server 8.8.8.8 # Set custom DNS server
Build Tools
# APK Signing
apksigner sign --ks keystore.jks app.apk
apksigner verify --verbose app.apk
# APK Analysis
aapt dump badging app.apk # Show APK manifest info
aapt dump resources app.apk # Show app resources
aapt dump xmltree app.apk AndroidManifest.xml # Show manifest XML
# APK Optimization
zipalign -v 4 input.apk output.apk # Optimize APK
# Bundletool (for App Bundles)
bundletool build-apks --bundle=app.aab --output=app.apks
bundletool install-apks --apks=app.apks
DDMS (Dalvik Debug Monitor Server)
Legacy tool mostly replaced by Android Studio profiling tools, but still useful for:
- Thread and heap monitoring
- Screen capturing
- Simulating phone calls and SMS
- File explorer functionality
- Location spoofing
SDK Manager in Command Line
# List installed and available packages
sdkmanager --list
# Install packages
sdkmanager "platform-tools" "platforms;android-33"
sdkmanager "system-images;android-33;google_apis;x86_64"
# Update all installed packages
sdkmanager --update
# Uninstall packages
sdkmanager --uninstall "platforms;android-30"
API Levels and Platform Versions
API Level | Version Name | Version Number | Key Features |
---|
33 | Tiramisu | Android 13 | Themed app icons, per-app language, improved privacy |
32 | Snow Cone | Android 12L | Large screen optimizations, taskbar |
31 | Snow Cone | Android 12 | Material You, Privacy Dashboard, approximate location |
30 | R | Android 11 | Conversation notifications, one-time permissions, wireless debugging |
29 | Q | Android 10 | Dark theme, gesture navigation, privacy controls |
28 | Pie | Android 9 | Indoor positioning, display cutout, multi-camera |
27 | Oreo | Android 8.1 | Neural networks API, shared memory API |
26 | Oreo | Android 8.0 | Picture-in-picture, notification channels, autofill |
24-25 | Nougat | Android 7.0-7.1.2 | Multi-window, notification replies, Vulkan API |
23 | Marshmallow | Android 6.0 | Runtime permissions, Doze mode, fingerprint authentication |
21-22 | Lollipop | Android 5.0-5.1 | Material Design, ART runtime, WebView independent updates |
19-20 | KitKat | Android 4.4-4.4.4 | Immersive mode, transitions, print framework |
16-18 | Jelly Bean | Android 4.1-4.3 | Project Butter, Google Now, restricted profiles |
14-15 | Ice Cream Sandwich | Android 4.0-4.0.4 | Unified UI for phones/tablets, face unlock |
10-13 | Honeycomb | Android 3.0-3.2.6 | Fragment API, action bar, animations framework |
8-9 | Gingerbread | Android 2.3-2.3.7 | NFC support, download manager, multiple cameras |
5-7 | Froyo/Eclair | Android 2.0-2.2 | HTML5 support, Live wallpapers, App2SD |
Key Android SDK Libraries and APIs
Core UI Components
// Setting up RecyclerView
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = MyAdapter(dataList)
// ViewPager2 with Fragments
val viewPager = findViewById<ViewPager2>(R.id.viewPager)
val adapter = ViewPagerAdapter(this)
viewPager.adapter = adapter
// BottomNavigationView with NavController
val bottomNav = findViewById<BottomNavigationView>(R.id.bottomNav)
val navController = findNavController(R.id.nav_host_fragment)
bottomNav.setupWithNavController(navController)
// TabLayout with ViewPager2
val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
val viewPager = findViewById<ViewPager2>(R.id.viewPager)
viewPager.adapter = ViewPagerAdapter(this)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = "Tab ${position + 1}"
}.attach()
Permissions Framework
// Declaring permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
// Runtime permission checking and requesting
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
CAMERA_PERMISSION_CODE
)
}
// Handling permission results
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
when (requestCode) {
CAMERA_PERMISSION_CODE -> {
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, proceed with camera operation
} else {
// Permission denied, handle accordingly
}
return
}
}
}
Data Storage APIs
Storage Option | Use Case | Code Example |
---|
SharedPreferences | Small key-value pairs | val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE) <br> prefs.edit().putString("key", "value").apply() |
Room Database | Structured data, complex queries | @Database(entities = [User::class], version = 1) <br> abstract class AppDatabase : RoomDatabase() { ... } |
File Storage | Raw file data, media files | openFileOutput("data.txt", Context.MODE_PRIVATE).use { it.write(data.toByteArray()) } |
ContentProviders | Sharing data between apps | contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ...) |
DataStore | Asynchronous, type-safe preferences | val dataStore = context.createDataStore("settings") <br> val preferenceFlow: Flow<Preferences> = dataStore.data |
Networking APIs
// Retrofit setup
interface ApiService {
@GET("users")
suspend fun getUsers(): List<User>
}
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
// Making network requests with coroutines
lifecycleScope.launch {
try {
val users = apiService.getUsers()
// Process users
} catch (e: Exception) {
// Handle error
}
}
// Using OkHttp interceptors
val client = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.addInterceptor { chain ->
val original = chain.request()
val request = original.newBuilder()
.header("Authorization", "Bearer $token")
.build()
chain.proceed(request)
}
.build()
Android Jetpack Components
Component | Purpose | Implementation |
---|
ViewModel | UI state holder | class MyViewModel : ViewModel() { ... } |
LiveData | Observable data | private val _data = MutableLiveData<String>() <br> val data: LiveData<String> = _data |
Room | Database abstraction | @Entity data class User(...) <br> @Dao interface UserDao { ... } |
WorkManager | Background processing | val workRequest = OneTimeWorkRequestBuilder<MyWorker>().build() <br> WorkManager.getInstance(context).enqueue(workRequest) |
Navigation | App navigation | findNavController().navigate(R.id.action_to_details) |
Paging | Load and display data | val flow = Pager(config) { UserPagingSource() }.flow |
DataStore | Data storage | val dataStore = context.createDataStore("settings") |
CameraX | Camera functionality | val preview = Preview.Builder().build() <br> preview.setSurfaceProvider(previewView.surfaceProvider) |
Hilt | Dependency injection | @AndroidEntryPoint class MainActivity : AppCompatActivity() { ... } |
Media and Graphics
// Loading images with Glide
Glide.with(context)
.load(imageUrl)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(imageView)
// MediaPlayer for audio playback
val mediaPlayer = MediaPlayer.create(context, R.raw.audio_file)
mediaPlayer.start()
mediaPlayer.setOnCompletionListener { mp -> mp.release() }
// ExoPlayer for streaming media
val player = ExoPlayer.Builder(context).build()
val mediaItem = MediaItem.fromUri(videoUrl)
player.setMediaItem(mediaItem)
player.prepare()
player.play()
// Canvas drawing
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
color = Color.RED
style = Paint.Style.FILL
}
canvas.drawCircle(centerX, centerY, radius, paint)
Location and Maps
// FusedLocationProvider for location updates
val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 10000)
.setWaitForAccurateLocation(false)
.setMinUpdateIntervalMillis(5000)
.build()
val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
// Process location
}
}
}
val client = LocationServices.getFusedLocationProviderClient(this)
client.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
// Google Maps setup
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
// Add a marker in Sydney
val sydney = LatLng(-34.0, 151.0)
mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 12f))
}
}
Notifications
// Create notification channel (Android 8.0+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "channel_id"
val channel = NotificationChannel(
channelId,
"Channel Name",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Channel Description"
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
// Build and show notification
val notificationBuilder = NotificationCompat.Builder(this, "channel_id")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Notification Title")
.setContentText("Notification Text")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
// Add action button
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
notificationBuilder.setContentIntent(pendingIntent)
// Create expandable notification
notificationBuilder.setStyle(NotificationCompat.BigTextStyle()
.bigText("This is a longer notification text that will be displayed when the notification is expanded"))
// Show notification
with(NotificationManagerCompat.from(this)) {
if (ActivityCompat.checkSelfPermission(applicationContext, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED) {
notify(notificationId, notificationBuilder.build())
}
}
Testing Tools and APIs
Unit Testing with JUnit and Mockito
// Basic JUnit test
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
// Testing a ViewModel with Mockito
@RunWith(MockitoJUnitRunner::class)
class UserViewModelTest {
@Mock
private lateinit var repository: UserRepository
@Rule
@JvmField
val instantExecutorRule = InstantTaskExecutorRule()
private lateinit var viewModel: UserViewModel
@Before
fun setup() {
viewModel = UserViewModel(repository)
}
@Test
fun `fetchUsers should update LiveData on success`() = runBlockingTest {
// Given
val users = listOf(User("John"), User("Jane"))
`when`(repository.getUsers()).thenReturn(users)
// When
viewModel.fetchUsers()
// Then
val value = viewModel.users.getOrAwaitValue()
assertEquals(users, value)
}
}
UI Testing with Espresso
// Basic Espresso test
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
@Test
fun clickButton_opensNewActivity() {
// Find the button and perform click
onView(withId(R.id.button_login))
.check(matches(isDisplayed()))
.perform(click())
// Verify new activity is launched with expected text
onView(withId(R.id.text_welcome))
.check(matches(withText("Welcome!")))
}
@Test
fun enterText_showsInTextField() {
// Type text in EditText
onView(withId(R.id.edit_text))
.perform(typeText("Hello Espresso!"), closeSoftKeyboard())
// Check if text is displayed
onView(withId(R.id.edit_text))
.check(matches(withText("Hello Espresso!")))
}
}
Benchmark Testing
// In app/build.gradle
androidTest {
targetProjectPath = ":benchmark"
}
// In benchmark module
@RunWith(AndroidJUnit4::class)
class MyBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()
@Test
fun benchmarkSomeFunction() {
val context = ApplicationProvider.getApplicationContext<Context>()
val packageName = "com.example.myapp"
benchmarkRule.measureRepeated(
packageName = packageName,
metrics = listOf(StartupTimingMetric()),
iterations = 5,
setupBlock = {
pressHome()
startActivityAndWait()
}
) {
// Code to benchmark
}
}
}
Build System and Gradle
Gradle Build Configuration
// build.gradle (Project level)
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.44'
}
}
// build.gradle.kts (Module level)
plugins {
id("com.android.application")
id("kotlin-android")
id("kotlin-kapt")
id("dagger.hilt.android.plugin")
}
android {
namespace = "com.example.myapp"
compileSdk = 33
defaultConfig {
applicationId = "com.example.myapp"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
buildFeatures {
viewBinding = true
dataBinding = true
compose = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
// Core Android dependencies
implementation("androidx.core:core-ktx:1.10.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.9.0")
// Jetpack components
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
implementation("androidx.room:room-runtime:2.5.1")
implementation("androidx.room:room-ktx:2.5.1")
kapt("androidx.room:room-compiler:2.5.1")
// Network libraries
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
// Image loading
implementation("com.github.bumptech.glide:glide:4.15.1")
// Testing
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:5.3.1")
testImplementation("androidx.arch.core:core-testing:2.2.0")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
Gradle Tasks and Commands
# Basic Gradle commands
./gradlew tasks # List available tasks
./gradlew clean # Clean build outputs
./gradlew build # Build all modules
./gradlew assembleDebug # Build debug APK
./gradlew assembleRelease # Build release APK
./gradlew installDebug # Install debug APK
./gradlew test # Run unit tests
./gradlew connectedAndroidTest # Run instrumented tests
# Dependency analysis
./gradlew app:dependencies # Show all dependencies
./gradlew app:dependencyUpdates # Check for updates (requires plugin)
# Custom tasks and automation
./gradlew lint # Run lint checks
./gradlew bundleRelease # Create AAB for Play Store
./gradlew appDistributionUploadRelease # Upload to Firebase App Distribution
Android App Bundle Configuration
android {
// ...
bundle {
language {
enableSplit = true
}
density {
enableSplit = true
}
abi {
enableSplit = true
}
}
dynamicFeatures = [":feature_one", ":feature_two"]
}
Common Challenges and Solutions
Memory Management
Challenge | Solution |
---|
Memory Leaks | Use LeakCanary, avoid static contexts, properly dispose subscriptions |
OutOfMemoryError | Optimize bitmap loading, use memory-efficient collections, implement pagination |
ANR (Application Not Responding) | Move heavy operations to background threads, use coroutines or WorkManager |
High memory usage | Implement object pooling, use SparseArray for maps with integer keys |
Performance Optimization
Area | Techniques |
---|
UI Performance | Use ConstraintLayout, avoid nested layouts, recycle views with RecyclerView |
Startup Time | Implement app startup, lazy initialization, deferred components |
Battery Usage | Batch network calls, use JobScheduler/WorkManager, optimize location updates |
Network Efficiency | Cache responses, implement offline support, compress data |
Database Operations | Use Room with coroutines, batch operations, proper indexing |
Security Best Practices
// Secure SharedPreferences with EncryptedSharedPreferences
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
applicationContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// Certificate pinning with OkHttp
val certificatePinner = CertificatePinner.Builder()
.add("example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
// Secure file storage
val file = File(context.filesDir, "sensitive_data.txt")
// Use file for internal storage (not accessible by other apps)
// Secure content provider
<provider
android:name=".MyContentProvider"
android:authorities="com.example.myapp.provider"
android:exported="false" />
Best Practices for SDK Usage
SDK Version Management
- Target the latest API level: Always target the most recent stable API level
- Set reasonable minSdk: Balance reach and feature set
- Handle version-specific code: Use
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.X)
pattern - Use AndroidX: Migrate from Support Library to AndroidX
- Implement compatibility libraries: Use Jetpack libraries for backward compatibility
Resource Optimization
- Density-specific drawables: Provide resources for different screen densities
- Vector drawables: Use when possible to reduce APK size
- String localization: Separate strings into locale-specific files
- Configuration qualifiers: Use for different screen sizes, orientations
- Resource shrinking: Enable in Gradle for release builds
SDK Tool Usage
- Use Lint: Run regular lint checks to identify potential issues
- Enable ProGuard/R8: Configure code shrinking and obfuscation
- Set up CI/CD: Automate builds and testing with GitHub Actions or similar
- Analyze APK: Use Android Studio’s APK Analyzer to identify size issues
- Profile your app: Use Android Profiler for CPU, memory, and network analysis
Resources for Further Learning
Official Documentation
Code Samples and Repos
Learning Paths
- Google Codelabs for Android Development
- Android Developers YouTube Channel
- Android Developers Blog
- Google I/O sessions and recordings