LearnThatStack Ace your next interview

Android Development.
Interview cheat sheet.

Quick reference for Android Development - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Mobile Development 23-section reference ~10 min read

Overview

Android is Google's open-source mobile operating system powering billions of devices worldwide. This cheatsheet covers essential Android development concepts using Java, focusing on the most critical topics for technical interviews. Whether you're building native Android apps or preparing for interviews, these concepts form the foundation of Android development.

1. Android Fundamentals

Android Architecture Layers

  • Linux Kernel: Core system services (drivers, power management, memory management)
  • Hardware Abstraction Layer (HAL): Standard interfaces exposing device hardware capabilities
  • Android Runtime (ART):
    • Ahead-of-Time (AOT) compilation for better performance
    • Improved garbage collection
    • Better debugging support
  • Native C/C++ Libraries: WebKit, OpenGL ES, SQLite, Media Framework
  • Java API Framework: Content Providers, View System, Activity Manager, etc.
  • System Apps: Dialer, SMS, Calendar, Camera

Four Application Components

  1. Activities:

    • Single screen with user interface
    • Extends AppCompatActivity or Activity
    • Example: Login screen, Settings page
  2. Services:

    • Background operations without UI
    • Types: Started Service, Bound Service, Foreground Service
    • Example: Music playback, file download
  3. Broadcast Receivers:

    • Responds to system-wide broadcast announcements
    • Can be registered in manifest or dynamically
    • Example: Battery low, WiFi connected
  4. Content Providers:

    • Manages shared app data
    • Provides data to other applications
    • Example: Contacts, Media Store

AndroidManifest.xml

<manifest package="com.example.app">
    <uses-permission android:name="android.permission.INTERNET" />
    
    <application
        android:icon="@mipmap/ic_launcher"
        android:theme="@style/AppTheme">
        
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

2. Activity Lifecycle

Lifecycle Methods

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Activity created, initialize UI
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        // Activity visible
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        // Activity interactive
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        // Activity losing focus
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        // Activity no longer visible
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Activity destroyed
    }
}

Common State Transitions

  • App Launch: onCreate() → onStart() → onResume()
  • Home Button: onPause() → onStop() → onSaveInstanceState()
  • Back Button: onPause() → onStop() → onDestroy()
  • Phone Call Interrupt: onPause() → onResume()
  • App Switch & Return: onPause() → onStop() → onRestart() → onStart() → onResume()
  • Configuration Change: onPause() → onStop() → onSaveInstanceState() → onDestroy() → onCreate() → onStart() → onRestoreInstanceState() → onResume()

3. Layouts and Views

Common Layouts

<!-- LinearLayout -->
<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView android:text="Hello" />
    <Button android:text="Click" />
</LinearLayout>

<!-- ConstraintLayout -->
<androidx.constraintlayout.widget.ConstraintLayout>
    <TextView
        android:id="@+id/textView"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

<!-- RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

View Binding

// Enable in build.gradle
android {
    viewBinding {
        enabled = true
    }
}

// In Activity
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        
        binding.button.setOnClickListener(v -> {
            binding.textView.setText("Clicked!");
        });
    }
}

4. Fragments

Fragment Lifecycle

public class MyFragment extends Fragment {
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        // Fragment attached to activity
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_my, container, false);
    }
    
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // View created, initialize UI components
    }
}

Fragment Transactions

// Add Fragment
getSupportFragmentManager().beginTransaction()
    .add(R.id.container, new MyFragment())
    .commit();

// Replace Fragment with backstack
getSupportFragmentManager().beginTransaction()
    .replace(R.id.container, new AnotherFragment())
    .addToBackStack(null)
    .commit();

5. Intents and Navigation

Explicit Intent

// Start Activity
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("key", "value");
startActivity(intent);

// Start Activity for Result
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            Intent data = result.getData();
            // Handle result
        }
    });
launcher.launch(intent);

Implicit Intent

// Open URL
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
startActivity(intent);

// Share text
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Share this!");
startActivity(Intent.createChooser(shareIntent, "Share via"));

6. Data Storage

SharedPreferences

// Write
SharedPreferences prefs = getSharedPreferences("MyPrefs", MODE_PRIVATE);
prefs.edit()
    .putString("key", "value")
    .putInt("count", 10)
    .apply();

// Read
String value = prefs.getString("key", "default");
int count = prefs.getInt("count", 0);

Room Database

// Entity
@Entity(tableName = "users")
public class User {
    @PrimaryKey(autoGenerate = true)
    public int id;
    
    @ColumnInfo(name = "user_name")
    public String name;
    
    public String email;
}

// DAO
@Dao
public interface UserDao {
    @Query("SELECT * FROM users")
    List<User> getAllUsers();
    
    @Insert
    void insertUser(User user);
    
    @Update
    void updateUser(User user);
    
    @Delete
    void deleteUser(User user);
}

// Database
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

// Usage
AppDatabase db = Room.databaseBuilder(context,
    AppDatabase.class, "database-name").build();

7. Networking

Retrofit

// API Interface
public interface ApiService {
    @GET("users/{id}")
    Call<User> getUser(@Path("id") int userId);
    
    @POST("users")
    Call<User> createUser(@Body User user);
}

// Setup
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

ApiService service = retrofit.create(ApiService.class);

// Usage
service.getUser(1).enqueue(new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        User user = response.body();
    }
    
    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // Handle error
    }
});

Permissions

// Check permission
if (ContextCompat.checkSelfPermission(this, 
    Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    
    // Request permission
    ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.CAMERA}, REQUEST_CODE);
}

// Handle result
@Override
public void onRequestPermissionsResult(int requestCode, 
    @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_CODE) {
        if (grantResults.length > 0 && 
            grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission granted
        }
    }
}

8. RecyclerView

Adapter Implementation

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<String> data;
    
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        
        public ViewHolder(View view) {
            super(view);
            textView = view.findViewById(R.id.textView);
        }
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_layout, parent, false);
        return new ViewHolder(view);
    }
    
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.textView.setText(data.get(position));
    }
    
    @Override
    public int getItemCount() {
        return data.size();
    }
}

// Setup RecyclerView
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new MyAdapter(dataList));

9. Services

Foreground Service

public class MyService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Create notification channel (Android O+)
        createNotificationChannel();
        
        // Create notification
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Service Running")
            .setSmallIcon(R.drawable.ic_notification)
            .build();
            
        startForeground(1, notification);
        
        // Do work
        return START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

// Start service
Intent serviceIntent = new Intent(this, MyService.class);
ContextCompat.startForegroundService(this, serviceIntent);

10. Broadcast Receivers

Dynamic Registration

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BATTERY_LOW.equals(intent.getAction())) {
            // Handle battery low
        }
    }
}

// Register
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_LOW);
registerReceiver(receiver, filter);

// Unregister
unregisterReceiver(receiver);

Static Registration (Manifest)

<receiver android:name=".BootReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

11. Architecture Components

ViewModel

public class MyViewModel extends ViewModel {
    private MutableLiveData<String> data = new MutableLiveData<>();
    
    public LiveData<String> getData() {
        return data;
    }
    
    public void loadData() {
        // Load data asynchronously
        data.setValue("Loaded data");
    }
}

// In Activity/Fragment
MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
viewModel.getData().observe(this, newData -> {
    // Update UI
    textView.setText(newData);
});

LiveData

// MutableLiveData
MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.setValue("Main thread update");
liveData.postValue("Background thread update");

// Transformations
LiveData<String> upperCaseData = Transformations.map(liveData, 
    input -> input.toUpperCase());

Data Binding

<!-- Enable in build.gradle -->
android {
    dataBinding {
        enabled = true
    }
}

<!-- Layout -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    
    <TextView
        android:text="@{user.name}"
        android:visibility="@{user.isVisible ? View.VISIBLE : View.GONE}" />
</layout>

12. Coroutines (Kotlin-Java Interop)

Basic Usage

// Launch coroutine from Java (using Kotlin interop)
// Requires Kotlin coroutines library

// In Kotlin helper class
class CoroutineHelper {
    fun doAsyncWork(callback: (String) -> Unit) {
        GlobalScope.launch {
            val result = withContext(Dispatchers.IO) {
                // Background work
                "Result"
            }
            withContext(Dispatchers.Main) {
                callback(result)
            }
        }
    }
}

// In Java
new CoroutineHelper().doAsyncWork(result -> {
    // Update UI with result
});

13. Threading

Handler and Looper

// Main thread handler
Handler mainHandler = new Handler(Looper.getMainLooper());

// Background thread
new Thread(() -> {
    // Do background work
    String result = performTask();
    
    // Update UI on main thread
    mainHandler.post(() -> {
        textView.setText(result);
    });
}).start();

// HandlerThread
HandlerThread handlerThread = new HandlerThread("BackgroundThread");
handlerThread.start();
Handler backgroundHandler = new Handler(handlerThread.getLooper());

AsyncTask (Deprecated but still asked)

private class MyAsyncTask extends AsyncTask<String, Integer, String> {
    @Override
    protected String doInBackground(String... params) {
        // Background thread
        publishProgress(50);
        return "Result";
    }
    
    @Override
    protected void onProgressUpdate(Integer... progress) {
        // UI thread
        progressBar.setProgress(progress[0]);
    }
    
    @Override
    protected void onPostExecute(String result) {
        // UI thread
        textView.setText(result);
    }
}

14. Content Providers

Query Content Provider

// Query contacts
Cursor cursor = getContentResolver().query(
    ContactsContract.Contacts.CONTENT_URI,
    null, null, null, null);

if (cursor != null && cursor.moveToFirst()) {
    do {
        String name = cursor.getString(
            cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
    } while (cursor.moveToNext());
    cursor.close();
}

15. Notifications

Creating Notifications

// Create channel (Android O+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel(
        CHANNEL_ID, "Channel Name", NotificationManager.IMPORTANCE_DEFAULT);
    notificationManager.createNotificationChannel(channel);
}

// Build notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setSmallIcon(R.drawable.ic_notification)
    .setContentTitle("Title")
    .setContentText("Message")
    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    .setAutoCancel(true);

// Show notification
NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, builder.build());

16. Material Design Components

Common Components

<!-- TextInputLayout -->
<com.google.android.material.textfield.TextInputLayout
    android:hint="Email"
    style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
    <com.google.android.material.textfield.TextInputEditText
        android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>

<!-- FloatingActionButton -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/fab"
    android:src="@drawable/ic_add"
    app:layout_anchor="@id/bottom_app_bar" />

<!-- BottomNavigationView -->
<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_navigation"
    app:menu="@menu/bottom_navigation_menu" />

17. Performance Optimization

Best Practices & Techniques

  1. RecyclerView Optimization:

    • Implement ViewHolder pattern correctly
    • Use DiffUtil for efficient updates
    • Set fixed size when possible: setHasFixedSize(true)
    • Use RecycledViewPool for nested RecyclerViews
  2. Memory Management:

    • Use WeakReference for Activity/Context references
    • Unregister all listeners in onDestroy()
    • Avoid memory leaks from static references
    • Use LeakCanary in development
  3. Image Optimization:

    • Use WebP format (30% smaller than PNG)
    • Implement proper image scaling
    • Use Glide or Picasso for efficient loading
    • Cache images appropriately
  4. Layout Performance:

    • Prefer ConstraintLayout over nested LinearLayouts
    • Use <merge> tags to reduce hierarchy
    • Enable hardware acceleration
    • Use ViewStub for rarely used views
  5. Code Optimization:

    • Enable R8/ProGuard for release builds
    • Use @Keep annotation for reflection-accessed code
    • Remove unused resources with shrinkResources
    • Use Android App Bundle for smaller downloads
  6. Data Structures:

    • Use SparseArray instead of HashMap<Integer, Object>
    • Use ArrayMap for small collections (<1000 items)
    • Prefer primitive types over boxed types

Memory Leak Prevention

public class MyActivity extends AppCompatActivity {
    private static WeakReference<MyActivity> weakActivity;
    
    // Avoid static references to activities
    // Use WeakReference if necessary
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Clean up resources
        handler.removeCallbacksAndMessages(null);
        if (asyncTask != null) {
            asyncTask.cancel(true);
        }
    }
}

18. Testing

Unit Testing

// JUnit test
@Test
public void addition_isCorrect() {
    assertEquals(4, 2 + 2);
}

// Mockito
@Test
public void testUserRepository() {
    UserDao mockDao = mock(UserDao.class);
    when(mockDao.getUser(1)).thenReturn(new User("Test"));
    
    UserRepository repository = new UserRepository(mockDao);
    User user = repository.getUser(1);
    
    assertEquals("Test", user.getName());
}

Instrumentation Testing

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
    @Rule
    public ActivityScenarioRule<MainActivity> rule = 
        new ActivityScenarioRule<>(MainActivity.class);
    
    @Test
    public void testButtonClick() {
        onView(withId(R.id.button)).perform(click());
        onView(withId(R.id.textView)).check(matches(withText("Clicked!")));
    }
}

19. Security Best Practices

  1. Use HTTPS for all network communications
  2. Store sensitive data encrypted (Android Keystore)
  3. Validate all inputs
  4. Use ProGuard to obfuscate code
  5. Implement certificate pinning for sensitive APIs
  6. Don't log sensitive information
  7. Use Android's permission system properly

Encryption Example

// Generate and store key in Android Keystore
KeyGenerator keyGenerator = KeyGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
    "MyKeyAlias",
    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .build();
keyGenerator.init(keyGenParameterSpec);
keyGenerator.generateKey();

20. Critical Interview Topics

Conceptual Questions

  1. What is Context in Android?

    • Interface to global information about application environment
    • Two types: Application Context and Activity Context
  2. Difference between Serializable and Parcelable?

    • Parcelable: Android-specific, faster, more efficient
    • Serializable: Java standard, slower, uses reflection
  3. What is ANR?

    • Application Not Responding
    • Occurs when UI thread blocked for >5 seconds
  4. Launch Modes

    • standard: New instance always created
    • singleTop: Reuse if on top of stack
    • singleTask: Only one instance in task
    • singleInstance: Only one instance in system
  5. Memory Leaks Common Causes

    • Static references to activities
    • Non-static inner classes
    • Unregistered listeners
    • Handler references

Code Questions Often Asked

// Singleton Pattern
public class Singleton {
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

// Custom View
public class CustomView extends View {
    private Paint paint;
    
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
    private void init() {
        paint = new Paint();
        paint.setColor(Color.RED);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(getWidth()/2, getHeight()/2, 100, paint);
    }
}

Quick Reference

Gradle Dependencies (Common)

dependencies {
    // AndroidX
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    
    // Material Design
    implementation 'com.google.android.material:material:1.9.0'
    
    // Architecture Components
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.6.1'
    implementation 'androidx.lifecycle:lifecycle-livedata:2.6.1'
    
    // Room
    implementation 'androidx.room:room-runtime:2.5.2'
    annotationProcessor 'androidx.room:room-compiler:2.5.2'
    
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    
    // Testing
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

Important Files Structure

app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/app/
│   │   ├── res/
│   │   │   ├── layout/
│   │   │   ├── values/
│   │   │   ├── drawable/
│   │   │   └── mipmap/
│   │   └── AndroidManifest.xml
│   ├── test/
│   └── androidTest/
├── build.gradle
└── proguard-rules.pro

Key Takeaways for Interviews

Must-Know Topics

  1. Activity/Fragment Lifecycle - Be able to draw and explain state transitions
  2. Memory Management - Understand leaks, weak references, and garbage collection
  3. Threading - Main thread, AsyncTask alternatives, Handlers, Coroutines
  4. Architecture Patterns - MVP, MVVM, Clean Architecture
  5. Performance - RecyclerView optimization, image loading, APK size reduction

Common Pitfalls to Avoid

  • Performing network operations on main thread
  • Not handling configuration changes properly
  • Memory leaks from inner classes and listeners
  • Ignoring ProGuard/R8 for production builds
  • Not testing on different screen sizes and API levels

Modern Android Development (2024)

  • Kotlin is now preferred over Java
  • Jetpack Compose for declarative UI
  • Coroutines for asynchronous programming
  • Hilt for dependency injection
  • Navigation Component for app navigation
  • WorkManager for background tasks

Interview Success Tip: Always discuss trade-offs when explaining solutions. Show understanding of performance implications, maintainability, and user experience considerations in your architectural decisions.

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime