val is immutable (read-only, like final in Java).
var is mutable (modifiable).
A data class automatically provides equals(), hashCode(), copy(), and toString().
It is useful for model classes (e.g., API responses).
Extension functions add behavior to existing classes without modifying them.
Exemple:
fun String.isEmailValid(): Boolean {
return this.contains("@") && this.contains(".")
}
Now, "test@example.com".isEmailValid() works.
-> lateinit is used for var and initialized later.
-> lazy is used for val and initialized only once when accessed.
lateinit var name: String // Must be initialized before use
Exemple:
val age: Int by lazy { 25 } // Only evaluated when accessed
Use Intent:
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("name", "Nancy")
startActivity(intent)
Second Activity Get Data
val name = intent.getStringExtra("name")
startActivityForResult() is deprecated in favor of ActivityResultLauncher.
Example using ActivityResultLauncher:
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activit
GONE: Hides the view and removes it from the layout.
INVISIBLE: Hides the view but still takes up space.
VISIBLE: The view is displayed.
WorkManager schedules background tasks that must run even if the app is killed.
Used for periodic syncing, data backup, etc.
SharedPreferences: Synchronous, not recommended for large data.
DataStore: Uses Coroutines, avoids ANR (App Not Responding) issues.
Example:
val dataStore = context.createDataStore(name = "settings")
Used for loading large data sets efficiently with RecyclerView.
Supports pagination from API or database.
Dispatchers.Main: Runs on UI thread.
Dispatchers.IO: Used for network/database operations.
Dispatchers.Default: Used for CPU-intensive tasks.
Example:
CoroutineScope(Dispatchers.IO).launch {
val data = fetchDataFromNetwork()
}
inline: Inlines the function at the call site, avoiding function call overhead.
noinline: Prevents specific lambda parameters from being inlined.
crossinline: Ensures that the lambda parameter does not return from the enclosing function.
? allows nullable values (String?).
!! forces a null-unsafe call (throws NullPointerException).
?. safely accesses properties (user?.name).
?: (Elvis operator) provides a default value (user?.name ?: "Guest").
sealed class allows different data types, while enum has fixed constants.
Declarative UI (simplifies UI development).
State management is easier.
No need for findViewById().
Less boilerplate code.
Use ViewModel (persists data across configuration changes).
Use onSaveInstanceState() for small data.
Set configChanges="orientation|screenSize" in Manifest (not always recommended).
Thread: Heavy, uses OS-level resources.
HandlerThread: Background thread with a Looper.
Coroutine: Lightweight, managed by Kotlin runtime, more efficient.
enqueue(): Asynchronous, runs in the background.
execute(): Synchronous, blocks the main thread.
The Elvis operator (?:) is used to provide a default value if an expression is null. It acts as a shorthand for handling null values.
Example:
val name: String? = null
val displayName = name ?: "Guest" // If name is null, "Guest" is used
println(dis
Coroutines in Kotlin are used for asynchronous programming. They are lightweight and prevent UI blocking.
Types of coroutines in Android:
GlobalScope.launch - Runs in the background but does not respect the lifecycle.
ViewModelScope.launch - Tied to the ViewModel lifecycle.
LifecycleScope.launch - Used within activities/fragments.
MainScope.launch - Custom scope used for UI updates.
Foreground Service: Used for tasks that require user attention (e.g., music player).
Background Service: Runs in the background (deprecated in newer Android versions).
JobIntentService: Used for background work.
WorkManager: Recommended for scheduled or background tasks.
Launch modes define how activities are launched. The four types are:
Standard – New instance created every time.
SingleTop – Reuses an existing instance if it's already on top.
SingleTask – Creates a new task and clears other activities.
SingleInstance – Ensures only one instance across all apps.
LiveData and MutableLiveData both are classes for observable data holders, but they differ in mutability. LiveData provides read-only access to the held data, while MutableLiveData allows modification of the data.
RxJava is a reactive programming library used for asynchronous operations.
Commonly used operators:
map() – Transforms data.
flatMap() – Flattens nested observables.
filter() – Filters items based on a condition.
debounce() – Reduces the number of emitted events.
Abstraction hides implementation details and shows only necessary information.
abstract class Vehicle {
abstract fun start()
}
class Car : Vehicle() {
override fun start() { println("Car starting") }
}
Encapsulation hides data and provides controlled access.
class BankAccount {
private var balance: Double = 1000.0
fun deposit(amount: Double) { balance += amount }
fun getBalance(): Double = balance
}
Here, balance is private, and external access is controlled.
Dagger: A powerful Dependency Injection (DI) framework for managing dependencies.
Hilt: A simplified DI tool built on Dagger, reducing boilerplate.
Use arguments with a Bundle to pass data to fragments.
val fragment = MyFragment().apply {
arguments = Bundle().apply { putString("key", "Hello") }
}
Access inside the fragment:
val data = arguments?.getString("key")
Abstraction is the process of hiding implementation details and showing only relevant information to the user. It focuses on what an object does rather than how it does it.
🚗 Car Example:
When you drive a car, you just use the steering wheel, accelerator, and brakes.
You don’t need to know how the engine, fuel injection, or braking mechanism works internally.
Abstraction: The internal working is hidden, and only essential functionalities are exposed.
Object-Oriented Programming (OOPs) is a programming paradigm based on the concept of objects, which are instances of classes. It is widely used in languages like Java, Kotlin, Python, C++, etc. and is the foundation of Android development.
4 Pillars of OOPs
OOPs is based on four main principles:
1️⃣ Encapsulation – Binding data and methods together
2️⃣ Abstraction – Hiding implementation details
3️⃣ Inheritance – Reusing code from existing classes
4️⃣ Polymorphism – One interface, multiple implementations