Kotlin
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Null Safety
-
Section 4: Object-Oriented Kotlin
-
Section 5: Functional Kotlin
-
Section 6: Coroutines
-
Section 7: Collections Deep Dive
-
Section 8: Type System Deep Dive
-
Section 9: Interop and Tooling
-
Section 10: Kotlin DSLs and Patterns
-
Section 11: Testing and Quality
-
Section 12: Server-Side Kotlin
-
Section 13: Practical Projects
-
Section 14: Interview Practice
-
Section 15: More Practice Exercises
-
Section 16: More Standard Library
-
Section 17: Multiplatform Kotlin
-
Section 18: kotlin.collections In Depth
-
Section 19: kotlin.text In Depth
-
Section 20: kotlin.ranges and kotlin.sequences
-
Section 21: kotlin.io and File Handling
-
Section 22: kotlinx.coroutines Deep Dive
-
Section 23: kotlin.reflect
-
Section 24: Android Development with Kotlin Overview
-
Section 25: Kotlin Multiplatform Deep Dive
-
Section 26: Kotlin for Backend Deep Dive
-
Section 27: Kotlin Design Patterns
-
Section 28: Advanced Language Features
-
Section 29: More Practice Exercises
-
Section 30: More Interview Practice
-
Section 31: Kotlin Type System Deep Dive
-
Section 32: Kotlin Null Safety Advanced
-
Section 33: Kotlin Testing Deep Dive
-
Section 34: Kotlin Build Tooling Deep Dive
-
Section 35: Kotlin Serialization
-
Section 36: Kotlin Performance Considerations
-
Section 37: Kotlin Native Overview
-
Section 38: Kotlin for Data and Scripting
-
Section 39: More Coroutines Practice
-
Section 40: More Android-Adjacent Patterns
-
Section 41: More Practical Projects
-
Section 42: More Design and Architecture Practice
-
Section 43: Kotlin Language Evolution
-
Section 44: More Interview and Review
-
Section 45: Kotlin Delegation Patterns Deep Dive
-
Section 46: Kotlin Annotations Deep Dive
-
Section 47: Kotlin for Gradle Plugin Development
-
Section 48: Kotlin Concurrency Beyond Coroutines
-
Section 49: Kotlin Compiler Internals
-
Section 50: Real-World Kotlin Case Studies
-
Section 51: Final Practice Projects
-
Section 52: Kotlin for Server-Side Reactive Programming
-
Section 53: More Practice and Drills
-
Section 54: Kotlin Security Practices
187: Navigation Component with Kotlin
I've been working on this movie discovery app, and right now, I'm stuck on a problem we've all faced: moving from a list of movies to a specific movie's detail page. In the past, I would have just written a bunch of FragmentTransaction code, but honestly? I'm tired of managing the back stack manually. It's a recipe for memory leaks and "Why did the app just close when I hit back?" bugs.
The Manual Fragment Headache
Just for a second, look at how I was doing this before I decided to use the Navigation Component. I had this block of code inside my MovieListFragment:
val detailFragment = MovieDetailFragment()
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container, detailFragment)
.addToBackStack(null)
.commit()
It looks simple enough for one screen, but as soon as I add a "Reviews" screen, a "Cast" screen, and a "Settings" page, my Activity becomes a giant traffic cop. I'm spending more time managing transactions than actually writing features. There's no single place to look at the app's flow; it's all buried in Kotlin files. I need a map.
Drawing the Map
So, I've added the Navigation Component. Instead of coding the transitions, I created a nav_graph.xml file. I dragged in two fragments: MovieListFragment and MovieDetailFragment. Then, I drew an arrow—an "Action"—from the list to the detail.
Now, the "map" knows that action_movieList_to_movieDetail is the valid path. I don't have to tell the FragmentManager to replace the container anymore. I just have to tell the NavController to follow that specific arrow. Here is how I'm triggering it now:
movieAdapter.onMovieClicked = { movie ->
findNavController().navigate(R.id.action_movieList_to_movieDetail)
}
That's much cleaner. The NavController handles the transaction, the back stack, and the animation. But wait—I've just realized a problem. The detail screen is loading, but it's empty. It doesn't know which movie I clicked on.
Avoiding the Bundle Trap
My first instinct was to use a Bundle. I've done it a thousand times. I'd put the movie ID in a bundle, pass it along, and then call arguments?.getString("movie_id") in the destination. But I hate that. If I typo "movie_id" as "mvoie_id" in one of those two files, the app crashes or shows a blank screen, and the compiler won't say a word to me.
I decided to use Safe Args. It's a Gradle plugin that generates "Directions" classes. Instead of using a raw ID for the action, it creates a class specifically for the MovieListFragment. Let's see how this changes the code:
// No more R.id.action...
val action = MovieListFragmentDirections.actionMovieListToMovieDetail(movieId = movie.id)
findNavController().navigate(action)
This is a game changer. If I change the argument type in the XML from a String to an Int, this Kotlin code will suddenly turn red. The compiler is now helping me manage my navigation logic. I'm not guessing what the destination expects anymore; the Directions class tells me exactly what's required.
Picking Up the Pieces
Now I just need to retrieve that ID on the other side. In MovieDetailFragment, I could use arguments, but since I'm using Safe Args, there's a delegated property that makes this feel like native Kotlin:
val args: MovieDetailFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val movieId = args.movieId
// Now I can fetch the movie details using this ID
}
The transition is seamless. I've gone from manually swapping fragments and crossing my fingers that the keys match, to a type-safe system where the entire flow of the app is visualized in one XML file and enforced by the compiler.
📋 Practical Task
Build a Type-Safe Movie Genre Navigator
You are tasked with adding a "Genre" navigation flow to the existing movie app. Follow these requirements:
- Create a new fragment called
GenreListFragmentand another calledGenreDetailFragment. - In the
nav_graph.xml, create a navigation action fromGenreListFragmenttoGenreDetailFragment. - Define an argument in the
GenreDetailFragmentdestination calledgenreName(Type: String). - Implement the click listener in
GenreListFragmentusing the generatedDirectionsclass to pass the selected genre's name to the detail fragment. - In
GenreDetailFragment, use theby navArgs()delegate to retrieve thegenreNameand display it in a TextView.
There are no comments for now.