PPrepLearn
Progress Β· 0/10 sections

🟑 🟑 Android Core Concepts

5 min read Β· Notion


πŸ“± Activity & Fragment Lifecycle

Activity Lifecycle callbacks (in order)
onCreate() β†’ onStart() β†’ onResume() β†’ [RUNNING]
β†’ onPause() β†’ onStop() β†’ onDestroy()
  • onCreate() β€” Initialize UI, bindings, ViewModel. Called once.
  • onStart() β€” Activity visible but not interactive.
  • onResume() β€” Activity in foreground and interactive.
  • onPause() β€” Another activity comes to foreground (save lightweight state here).
  • onStop() β€” Activity no longer visible (save heavier state here).
  • onDestroy() β€” Activity is finishing or being destroyed by system.
Fragment Lifecycle vs Activity Lifecycle

Fragment has additional callbacks:

  • onAttach() β†’ onCreate() β†’ onCreateView() β†’ onViewCreated() β†’ onStart() β†’ onResume()
  • onPause() β†’ onStop() β†’ onDestroyView() β†’ onDestroy() β†’ onDetach()

Key difference: onDestroyView() destroys the view hierarchy but the Fragment instance survives (e.g., in backstack). Always clear view references in onDestroyView() to avoid memory leaks.

What are Launch Modes in Android?

Defined in AndroidManifest.xml via android:launchMode:

ModeBehavior
standardNew instance always created (default)
singleTopReuses top-of-stack instance if same; calls onNewIntent()
singleTaskSingle instance per task; clears tasks above it; calls onNewIntent()
singleInstanceSingle instance in its own task, no other activities in same task
What is the AndroidManifest.xml?

The manifest declares:

  • App components (Activities, Services, Receivers, Providers)
  • Required permissions
  • Hardware/software features required
  • App metadata (app ID, version, min/target SDK)
  • Entry point Activity (intent-filter with MAIN + LAUNCHER)

πŸ”„ Intents

Explicit vs Implicit Intents
  • Explicit: Directly specifies the target component (class name).
startActivity(Intent(this, DetailActivity::class.java))
  • Implicit: Declares an action; the system finds the matching component.
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
startActivity(intent)
How to pass data between Activities?
// Sending
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("USER_ID", 42)
startActivity(intent)
 
// Receiving
val userId = intent.getIntExtra("USER_ID", -1)

For complex objects, use Parcelable (faster on Android) or Serializable. Prefer @Parcelize annotation with the Kotlin plugin.


πŸ“Ό RecyclerView

How does RecyclerView work?

RecyclerView recycles View objects using the ViewHolder pattern:

  1. RecyclerView.Adapter creates ViewHolder objects (inflating views).
  2. onBindViewHolder() binds data to the ViewHolder.
  3. When an item scrolls off screen, its ViewHolder is put in a RecycledViewPool.
  4. New items are bound by reusing pooled ViewHolders β€” avoiding costly inflate() calls.

Always use DiffUtil for efficient list updates instead of notifyDataSetChanged().

What is DiffUtil?

DiffUtil computes the difference between two lists and dispatches minimal update operations. It runs on a background thread with AsyncListDiffer or ListAdapter:

class MyAdapter : ListAdapter<Item, MyViewHolder>(ItemDiffCallback()) {
    class ItemDiffCallback : DiffUtil.ItemCallback<Item>() {
        override fun areItemsTheSame(a: Item, b: Item) = a.id == b.id
        override fun areContentsTheSame(a: Item, b: Item) = a == b
    }
}

πŸ’Ύ Storage

Room Database architecture

Room is a Jetpack abstraction over SQLite with three main components:

  • Entity (@Entity): Data class mapped to a DB table.
  • DAO (@Dao): Interface with @Query, @Insert, @Update, @Delete methods.
  • Database (@Database): Abstract class extending RoomDatabase, holds DAOs.
@Entity
data class User(@PrimaryKey val id: Int, val name: String)
 
@Dao
interface UserDao {
    @Query("SELECT * FROM user") fun getAll(): Flow<List<User>>
    @Insert suspend fun insert(user: User)
}

DAO methods can be suspend functions or return Flow for reactive updates.

Serializable vs Parcelable
  • Serializable: Java standard, uses reflection, slower, more GC pressure.
  • Parcelable: Android-specific, manual marshaling, ~10x faster for IPC/Intent passing.

Use @Parcelize from Kotlin Android Extensions to auto-generate Parcelable:

@Parcelize
data class User(val id: Int, val name: String) : Parcelable

πŸ“‘ Services & Background Work

Types of Services
TypeDescription
Foreground ServiceVisible to user via notification; survives app backgrounding
Background ServiceLimited by OS on API 26+
Bound ServiceClient-server model; stops when all clients unbind
WorkManager vs Service vs JobScheduler
  • WorkManager: Recommended for guaranteed deferred background work (even after reboot). Supports chaining, constraints (network, battery), and backoff.
  • Service: Real-time work while app is running.
  • JobScheduler: System-level API for scheduled jobs (WorkManager uses it internally on Android 6+).

For most use cases, prefer WorkManager.

Broadcast Receivers

Components that respond to system-wide broadcast announcements:

  • Registered in manifest (static) or registerReceiver() (dynamic).
  • Examples: ACTION_BOOT_COMPLETED, CONNECTIVITY_CHANGE, BATTERY_LOW.
  • Static receivers are restricted on API 26+ for implicit broadcasts.

Always unregister dynamic receivers in onStop() or onDestroy() to prevent leaks.


πŸ” Permissions

Runtime Permissions flow
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
    != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
        arrayOf(Manifest.permission.CAMERA), REQUEST_CODE)
}
 
override fun onRequestPermissionsResult(code: Int, permissions: Array<String>, results: IntArray) {
    if (results[0] == PackageManager.PERMISSION_GRANTED) { /* proceed */ }
}

On API 30+, use ActivityResultContracts.RequestPermission() with the Activity Result API.

Related