Skip to content

How Do You Master Android Fundamentals When Everyone Only Teaches Jetpack Compose?

The Problem

I’ve been an Android developer for three years. I can build features. I can ship apps. But when a senior engineer asked me to explain the difference between Activity and Fragment lifecycle, I froze.

Then came the interview. They asked about memory leaks in Android. I mentioned static references but couldn’t explain the underlying garbage collection mechanism. They asked why we use coroutines instead of callbacks. I said “because it’s cleaner” but couldn’t articulate the actual reasoning.

I realized I had a fundamental gap. I learned Android through Jetpack Compose tutorials. Modern courses skip the “old stuff.” They show you how to build UI with @Composable functions but never explain what happens underneath.

The problem became obvious when I tried to debug a production crash. The stack trace mentioned FragmentManager and onDestroy. I had no idea what those meant. I was using Compose Navigation, so why did I need to understand fragments?

What I Did Wrong

My learning path looked like this:

Jetpack Compose tutorials → Build UI → Copy Compose patterns → Ship app

I skipped everything that came before Compose. I thought:

  • “Activities are legacy, Compose handles that”
  • “Fragments are old, I use Compose Navigation”
  • “Memory management is automatic, why learn it?”

This worked until it didn’t. I couldn’t answer interview questions. I couldn’t debug complex issues. I couldn’t understand why my app crashed on configuration changes.

The worst part? Google removed their advanced Android training courses from 2017. There’s a gap in structured learning resources. Modern tutorials focus on Compose, but production apps still run on Activities, Fragments, and the Android framework.

What Actually Works

I asked on r/androiddev how to fill my knowledge gaps. The answer was surprisingly simple:

“Read the Android documentation at developer.android.com. Everything you listed is described there in detail.”

The official documentation covers what modern courses skip:

  • Activity lifecycle (onCreate, onStart, onResume, onPause, onStop, onDestroy)
  • Fragment lifecycle and FragmentManager
  • Services (started, bound, foreground)
  • BroadcastReceiver
  • ContentProvider
  • Memory management and garbage collection

These fundamentals haven’t changed since Android’s beginning. Compose builds on top of them.

Understanding Lifecycle Through Logging

The first thing I did was create a test Activity and log every lifecycle method:

LifecycleAwareActivity.kt
class LifecycleAwareActivity : AppCompatActivity() {
private const val TAG = "LifecycleDemo"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate: Activity created")
// Called when activity is first created
// savedInstanceState is null on first start, non-null on recreation
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart: Activity becoming visible")
// Activity is visible but not in foreground
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume: Activity in foreground, user can interact")
// Activity is ready for user interaction
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause: Activity losing focus")
// Another activity is coming to foreground
// Save persistent data here - might not return
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop: Activity no longer visible")
// Activity is completely obscured
// Release resources that aren't needed when invisible
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy: Activity being destroyed")
// Activity is finishing or being destroyed by system
// Clean up all resources
}
}

I rotated the screen, opened other apps, pressed home, and watched the logs. This taught me more than any tutorial.

The Memory Leak That Taught Me Garbage Collection

I found this code in our codebase:

LeakHelper.kt - Memory leak example
class LeakHelper {
companion object {
private var activity: Activity? = null // LEAK!
fun setActivity(act: Activity) {
activity = act
}
}
}

This leaks memory. The static reference holds the Activity, preventing garbage collection. When the Activity is destroyed, it stays in memory.

The fix:

SafeHelper.kt - Fixed memory leak
class SafeHelper(private val context: Context) {
// Use application context to avoid activity leaks
fun doSomething() {
// context is safe because it's application-level
}
}
// Alternative: WeakReference for optional activity reference
class WeakReferenceHelper(activity: Activity) {
private val activityRef = WeakReference(activity)
fun getActivity(): Activity? = activityRef.get()
}

Understanding why this fixes the leak required learning about Android’s garbage collection. The official documentation explained memory management patterns that I had been blindly avoiding.

Fragment Communication Done Right

My biggest confusion was Fragment communication. I used to do this:

HostActivity.kt - WRONG: Direct fragment reference
class HostActivity : AppCompatActivity() {
private var myFragment: MyFragment? = null
fun updateFragment() {
myFragment?.updateData() // Can crash if fragment is recreated
}
}

This crashes when the Fragment is recreated (screen rotation, system kills app in background). The correct approach uses ViewModel:

SharedViewModel.kt - Correct approach
class SharedViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun updateData(newData: String) {
_data.value = newData
}
}
class MyFragment : Fragment() {
private val sharedViewModel: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
sharedViewModel.data.observe(viewLifecycleOwner) { data ->
// Update UI safely
}
}
}

The documentation explained that ViewModel survives configuration changes. This is why modern architecture uses ViewModel for communication.

The Learning Path That Worked

After struggling with scattered tutorials, I created a structured approach:

Week 1-2: Activity and Fragment lifecycles

  • Built apps that survive configuration changes
  • Implemented proper state saving/restoration
  • Understood task and back stack behavior

Week 3-4: Services and BroadcastReceiver

  • Created started and bound services
  • Implemented inter-process communication
  • Handled system broadcasts

Week 5-6: Memory Management

  • Profiled existing apps for memory issues
  • Implemented LeakCanary
  • Fixed common leak patterns

Week 7-8: Architecture Patterns

  • Studied MVC, MVP, MVVM
  • Implemented each pattern manually
  • Understood why MVVM won for Android

Week 9-10: Dependency Injection

  • Understood the problem DI solves
  • Implemented manual DI before using Hilt/Dagger
  • Studied service locator vs dependency injection

The key was reading the official docs, then building small test apps to verify understanding.

Secondary Resources

Beyond developer.android.com, these resources filled gaps:

Books:

  • “Android Programming: The Big Nerd Ranch Guide” - systematic fundamentals
  • “Effective Java” by Joshua Bloch - essential for understanding Android’s design patterns
  • “Clean Architecture” by Robert Martin - architectural patterns

Practical exercises:

  • Built a complete app using only traditional Views (no Compose)
  • Implemented lifecycle-aware components from scratch
  • Debugged a deliberately memory-leaking app
  • Wrote a custom View

The official documentation is authoritative. Books provide structured learning. Building projects cements understanding.

Why This Matters

Understanding fundamentals provides advantages I didn’t expect:

  1. Debugging Compose issues: When Compose behaves unexpectedly, understanding the underlying View system helps diagnose problems

  2. Interview success: Companies still ask about lifecycle, memory leaks, and architectural decisions

  3. Legacy code maintenance: Many production apps use traditional architectures and will for years

  4. Informed decisions: Knowing both approaches lets you choose the right tool for each situation

  5. Framework understanding: Understanding why Jetpack was created helps you use it more effectively

Common Mistakes I Made

Mistake 1: Skipping to Compose too early

I should have learned fundamentals first, then appreciated what Compose simplifies. The “magic” of Compose makes more sense when you understand what it replaces.

Mistake 2: Ignoring the “why”

I memorized lifecycle methods but didn’t understand why each state exists. The documentation explains what system events trigger transitions. That knowledge matters for debugging.

Mistake 3: Copy-paste learning

I copied code without understanding. When I typed out examples and modified them, I learned how behavior changes. Active practice beats passive copying.

Mistake 4: Not reading source code

The Android framework source is readable and educational. Using “Go to Declaration” in Android Studio to explore implementation taught me more than any tutorial.

Mistake 5: Avoiding legacy projects

Legacy code is the best teacher. I volunteered to maintain older codebases and saw real-world patterns and problems that modern tutorials never cover.

Summary

In this post, I showed how to learn Android fundamentals when modern tutorials focus only on Jetpack Compose. The key point is reading the official documentation at developer.android.com, which covers Activity, Fragment, Service lifecycles, and core concepts in detail.

The fundamentals haven’t changed since Android’s beginning. They form the foundation that modern tools build upon. Without understanding them, you can build features but can’t explain why things work the way they do, debug subtle lifecycle bugs, or maintain legacy codebases.

Start with lifecycle, progress to memory management, and always understand the “why” behind each concept. This foundation will make you a better developer regardless of which UI framework you use.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments