Building a Flutter Map App: MVVM Architecture, State Management, and Real-Time Location Tracking
Building a robust Flutter map application means not only creating an engaging UI but also implementing a solid architecture that handles location services, permissions, and app lifecycle events. In this article, we’ll explain how MapMotion Flutter is built using the MVVM pattern with state management powered by flutter_bloc Cubits. We’ll also explore how dependency injection, real-time location tracking, and dynamic UI updates create a fluid and responsive experience. For the full source code, check out our GitHub repository.
Architectural Overview: MVVM in Action
To ensure a clean separation of concerns, MapMotion Flutter adopts the Model-View-ViewModel (MVVM) architecture:
- Model: Contains the data structures and business logic.
- ViewModel (Cubits): Manages the application state and acts as a bridge between the Model and the UI. Here, our Cubits handle permissions and location updates.
- View: Comprises the UI components, such as the interactive map and animation controllers.
Using get_it for dependency injection ensures that our services and Cubits (both registered as lazy singletons) are instantiated only when needed, promoting efficiency and testability.
Packages and Their Roles
The project leverages several key packages, each addressing a specific need:
- get_it: Provides a dependency injection framework to manage our singletons (Cubits and services).
- geolocator: Retrieves the device’s current location, essential for map interactions.
- equatable: Simplifies state comparisons in our Cubits without relying on code generation.
- flutter_bloc: Implements the Cubit-based state management pattern for handling business logic.
- flutter_map: Renders interactive maps and supports dynamic mapping features.
- latlong2: Offers latitude and longitude coordinate management.
- flutter_map_animations: Facilitates smooth animations on the map.
- lottie: Powers engaging, animated markers that enhance the visual appeal.
- soft_edge_blur: Adds subtle visual effects to improve the overall UI aesthetics.
Handling Location Permissions
Location services are the heartbeat of any map application. To access these, the user must grant location permissions. MapMotion Flutter uses a dedicated PermissionCubit that:
- Requests and monitors location permissions: It handles all possible states — granted, denied, or permanently denied.
- Controls navigation based on permission state: For example, if permission is denied, the app presents a dedicated screen prompting the user to update their settings. When permission is granted, the user is directed to the map view.
This permission logic is abstracted through service interfaces, ensuring that the Cubit remains focused solely on state management.
State Management with Cubits and Dependency Injection
Two primary Cubits drive our business logic:
PermissionCubit
- Role: Manages the state of location permissions.
- Uses flutter_bloc to maintain states such as PermissionGranted or PermissionDenied.
- Interfaces with a permissions service to request and update permission states.
- Registered as a lazy singleton with get_it for consistent, on-demand instantiation.
LocationCubit
- Role: Oversees real-time location updates.
- Listens to the device’s location using the geolocator package.
- Leverages StreamSubscription to monitor changes continuously — even when the app moves to the background.
- Uses equatable for precise state comparisons.
- Also, set it up as a lazy singleton through get_it.
Both Cubits communicate with their respective services via well-defined interfaces. This abstraction not only keeps business logic modular and testable but also simplifies future updates and maintenance.
Mapping and UI Integration
The user interface ties everything together. In our MapView (view code available here), we integrate the business logic into an interactive map experience:
- Animated Markers: The map employs Lottie for creating dynamic and visually engaging markers.
- Dynamic Path Tracking: Real-time location updates from LocationCubit are rendered on the map, allowing users to see their path dynamically drawn.
- Animation Controllers: Leveraging flutter_map_animations and soft_edge_blur, the UI provides smooth transitions and enhanced visual effects.
By linking directly to the code in our GitHub repository, readers can easily explore how each component fits together.
Video Walkthroughs
For those who prefer a visual deep dive, check out our video walkthroughs:
- Handling Location, Permissions & App Lifecycle (Part 1):
Watch on YouTube
- Interactive Maps, Animations & Path Tracking (Part 2):
Watch on YouTube
These videos complement the written guide by offering a step-by-step explanation of both the business logic and the UI integration.
Conclusion
MapMotion Flutter exemplifies how a well-structured architecture can lead to an intuitive, responsive, and maintainable map application. By combining the MVVM pattern with robust state management through Cubits, dependency injection with get_it, and a suite of powerful packages, we’ve built a system that not only performs well but is also easy to extend and maintain.
Get Alper Efe Sahin’s stories in your inbox
Join Medium for free to get updates from this writer.
Explore the full project on GitHub to see the complete code in action, and feel free to contribute or share feedback.











