<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Blazebrain</title>
    <description>The latest articles on DEV Community by Blazebrain (@blazebrain).</description>
    <link>https://dev.to/blazebrain</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F742209%2F97e8a4f2-2231-494b-993c-9f6b304b8e01.JPG</url>
      <title>DEV Community: Blazebrain</title>
      <link>https://dev.to/blazebrain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blazebrain"/>
    <language>en</language>
    <item>
      <title>Mastering the Art of Debugging in Flutter(Part Three)</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Wed, 04 Mar 2026 05:35:21 +0000</pubDate>
      <link>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-three-3kae</link>
      <guid>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-three-3kae</guid>
      <description>&lt;p&gt;Mastering the Widget World&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Welcome back to our journey through the art of debugging! In the previous parts, we explored general debugging principles and tackled network-related issues. Now, we're diving into the heart of Flutter development: &lt;strong&gt;widgets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Widgets are the building blocks of any Flutter application. Understanding their behavior and knowing how to troubleshoot their peculiarities is essential for building polished and efficient apps. In this article, we'll delve into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging common widget errors
&lt;/li&gt;
&lt;li&gt;Optimizing build methods for performance
&lt;/li&gt;
&lt;li&gt;Managing state effectively
&lt;/li&gt;
&lt;li&gt;The importance of keys in Flutter
&lt;/li&gt;
&lt;li&gt;Handling widget nesting and layout issues
&lt;/li&gt;
&lt;li&gt;Utilizing Flutter's layout system and debugging tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ready to master the widget world? Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Debugging Common Widget Errors&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While widgets offer incredible flexibility and power, they can also be a source of errors that impact performance and user experience. Recognizing and addressing these issues is crucial.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Build Method Performance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The build() method is the heart of a widget—it's where the UI is defined. However, excessive rebuilds can significantly impact performance. Here's how to optimize it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Profile the Build Method&lt;/strong&gt;: Use the Flutter DevTools Performance overlay to identify widgets that rebuild frequently.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimize State Changes&lt;/strong&gt;: Reduce the number of times setState() is called. Consider using immutable data structures to prevent unnecessary rebuilds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage const Constructors&lt;/strong&gt;: Use const constructors for immutable widgets to improve performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;State Management Inconsistencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Understanding the nuances between StatefulWidget and StatelessWidget is crucial.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;StatefulWidget&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Holds a state&lt;/strong&gt; that can change over time.
&lt;/li&gt;
&lt;li&gt;Creates a separate State object.
&lt;/li&gt;
&lt;li&gt;Uses setState() to trigger UI updates when the state changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;StatelessWidget&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Immutable&lt;/strong&gt; and doesn't hold any state.
&lt;/li&gt;
&lt;li&gt;Suitable for widgets that don't require dynamic updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Common Issues&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overusing StatefulWidget&lt;/strong&gt;: This can lead to unnecessary rebuilds and performance hits.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect Use of setState()&lt;/strong&gt;: Calling it too frequently or from the wrong context can cause unexpected behavior.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Leakage&lt;/strong&gt;: Exposing internal state can lead to unpredictable UI updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Importance of Keys&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Keys are unique identifiers assigned to widgets to help Flutter efficiently manage the widget tree during rebuilds.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Understanding Keys&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: They help Flutter distinguish between widgets, preserving state and avoiding unnecessary rebuilds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Types&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LocalKey&lt;/strong&gt;: Unique within the widget tree.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GlobalKey&lt;/strong&gt;: Accessible from anywhere in the app, useful for complex scenarios.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Why Keys Matter&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preserving State&lt;/strong&gt;: Maintains the state of widgets during rebuilds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimizing Performance&lt;/strong&gt;: Reduces unnecessary widget recreations.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managing Animations&lt;/strong&gt;: Essential for animating lists or reordering items smoothly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Common Issues&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missing Keys&lt;/strong&gt;: Can lead to performance issues and unexpected behavior.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect Key Usage&lt;/strong&gt;: Using keys improperly can cause state preservation problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Widget Nesting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While Flutter promotes building UIs by composing widgets, excessive nesting can impact performance and readability.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Optimizing Widget Nesting&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Break Down Complex Widgets&lt;/strong&gt;: Divide large widgets into smaller, reusable components.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Layout Builders&lt;/strong&gt;: Employ LayoutBuilder to create dynamic layouts based on available space.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider Custom Paint&lt;/strong&gt;: For performance-critical scenarios, use CustomPaint to draw directly on the canvas.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create Custom Widgets&lt;/strong&gt;: Encapsulate complex logic to improve code reusability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Understanding Flutter’s Layout System&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Flutter's layout system determines how widgets are arranged, sized, and positioned on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Layout Phases&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Constraints Flow Down&lt;/strong&gt;: Parents set constraints for their children.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sizes Flow Up&lt;/strong&gt;: Children determine their own size within the constraints and pass it back up.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parent Sets Position&lt;/strong&gt;: Parent decides where to position the child.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Constraints and Box Constraints&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constraints&lt;/strong&gt;: Represent the maximum and minimum sizes a widget can be.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Box Constraints&lt;/strong&gt;: A range of permissible sizes for a widget.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negotiation&lt;/strong&gt;: Widgets negotiate with their parents to determine their final size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Layout Algorithms&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Flutter provides several layout widgets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row&lt;/strong&gt;: Arranges children horizontally.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Column&lt;/strong&gt;: Arranges children vertically.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack&lt;/strong&gt;: Overlays children on top of each other.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: A versatile widget for styling, positioning, and sizing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded&lt;/strong&gt;: Expands a child of a Row, Column, or Flex to fill the available space.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flex&lt;/strong&gt;: A flexible layout model with customizable alignment and distribution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Handling Layout Issues and Overflows&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Layout issues are common challenges. Understanding the root causes helps in creating responsive UIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Overflow Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You've probably seen the dreaded "A RenderFlex overflowed..." error. It occurs when a child widget exceeds the space allocated by its parent.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Common Causes&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Missing constraints.
&lt;/li&gt;
&lt;li&gt;Children with fixed sizes in flexible parents.
&lt;/li&gt;
&lt;li&gt;Overlapping widgets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solutions&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Expanded or Flexible&lt;/strong&gt;: Wrap children in Expanded or Flexible to distribute space.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust Constraints&lt;/strong&gt;: Modify parent constraints or child sizes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scroll Widgets&lt;/strong&gt;: Wrap content in SingleChildScrollView if necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Alignment Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Proper alignment ensures that widgets appear where they should.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Common Issues&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Incorrect use of alignment properties.
&lt;/li&gt;
&lt;li&gt;Misunderstanding how Row, Column, or Stack layouts work.
&lt;/li&gt;
&lt;li&gt;Overlapping widgets due to improper positioning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solutions&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Experiment with Alignment&lt;/strong&gt;: Use MainAxisAlignment and CrossAxisAlignment.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Positioned Widgets&lt;/strong&gt;: In a Stack, use Positioned to place widgets precisely.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout Builders&lt;/strong&gt;: Use LayoutBuilder for responsive designs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Responsive Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Building UIs that adapt to different screen sizes is essential.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Techniques&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MediaQuery&lt;/strong&gt;: Access device dimensions and orientation.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LayoutBuilder&lt;/strong&gt;: Build layouts that adapt to size constraints.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AspectRatio&lt;/strong&gt;: Maintain consistent aspect ratios across devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Utilizing Flutter's Debugging Tools&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Flutter Widget Inspector&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Widget Inspector allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visualize Widget Trees&lt;/strong&gt;: See the hierarchy of widgets.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect Properties&lt;/strong&gt;: Examine widget properties and constraints.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose Layout Issues&lt;/strong&gt;: Identify where overflows or misalignments occur.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Layout Explorer&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visualize Constraints&lt;/strong&gt;: Understand how constraints affect layout.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect Sizes&lt;/strong&gt;: See exact dimensions of widgets.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug Alignment&lt;/strong&gt;: Check how widgets are aligned within their parents.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Performance Profiling&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identify Bottlenecks&lt;/strong&gt;: Use the Performance tab in DevTools.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze Rebuilds&lt;/strong&gt;: Check how often widgets rebuild.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Rendering&lt;/strong&gt;: Ensure smooth animations and transitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Incorrect Widget Usage&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Using widgets correctly is key to a smooth Flutter experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Incorrect Widget Properties&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Providing incorrect values can cause unexpected rendering.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Using negative values for padding or margin.
&lt;/li&gt;
&lt;li&gt;Setting flex properties improperly in Flex widgets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refer to Documentation&lt;/strong&gt;: Ensure you're using properties as intended.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Inputs&lt;/strong&gt;: Check values before assigning them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Mismatched Widget Types&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Combining incompatible widgets can lead to errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Placing a Text widget directly under a Row without wrapping it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Appropriate Containers&lt;/strong&gt;: Wrap widgets in Expanded, Flexible, or Container as needed.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand Parent Constraints&lt;/strong&gt;: Know what each parent widget expects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Ignoring Widget Lifecycle Methods&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lifecycle methods like initState(), didUpdateWidget(), and dispose() are crucial.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Common Mistakes&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Failing to dispose of controllers or listeners.
&lt;/li&gt;
&lt;li&gt;Not updating state when dependencies change.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implement Lifecycle Methods&lt;/strong&gt;: Override methods as needed.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Up Resources&lt;/strong&gt;: Dispose of any resources to prevent memory leaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Widgets are at the core of Flutter development, and mastering them is essential for building high-quality apps. By understanding common widget errors, optimizing build methods, managing state effectively, and utilizing Flutter's debugging tools, you're well on your way to becoming a Flutter pro.&lt;/p&gt;

&lt;p&gt;Remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep your widget tree optimized.
&lt;/li&gt;
&lt;li&gt;Use keys wisely.
&lt;/li&gt;
&lt;li&gt;Manage state thoughtfully.
&lt;/li&gt;
&lt;li&gt;Leverage Flutter's powerful tools to debug and optimize your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for the next part of this series, where we'll explore advanced debugging techniques and performance optimization!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions or need further assistance, feel free to reach out. I'm always here to help!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Connect with me on &lt;a href="https://twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/david-adegoke/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; for more Flutter tips and tutorials.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>debugging</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Navigating the Network Maze(Part Two)</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Mon, 11 Aug 2025 05:59:33 +0000</pubDate>
      <link>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-two-36gf</link>
      <guid>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-two-36gf</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Welcome back to our series on the art of debugging! In the previous part, we laid the foundation by understanding what debugging is and you got to know powerful the Flutter DevTools is. This time, we're diving deeper into a specific type of error that many developers encounter: &lt;strong&gt;network-related issues&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Network calls are the lifeblood of many applications. When they malfunction, it can frustrate your users and be a real headache to troubleshoot. By equipping ourselves with the right tools and knowledge, you can effectively navigate this network maze.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common network-related errors
&lt;/li&gt;
&lt;li&gt;Leveraging the Dart DevTools Network page
&lt;/li&gt;
&lt;li&gt;Handling async/await and Dart zones
&lt;/li&gt;
&lt;li&gt;Debugging HTTP requests and responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ready to dive in? Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Common Network-Related Errors&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;During development, you might run into various network issues that can be tricky to diagnose. Recognizing and understanding these errors is the first step toward effective debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Connection Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Timeouts: Requests exceeding the specified time limit. This could be due to slow server response or poor network connectivity.
&lt;/li&gt;
&lt;li&gt;Network Outages or Instability: Temporary loss of network connection can disrupt your app's ability to communicate with the server.
&lt;/li&gt;
&lt;li&gt;Incorrect DNS Resolution: Misconfigured DNS settings can prevent your app from reaching the intended server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Request Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Invalid URLs or Endpoints: Typos or incorrect paths in your API endpoints.
&lt;/li&gt;
&lt;li&gt;Incorrect HTTP Methods: Using the wrong HTTP method (e.g., using GET instead of POST).
&lt;/li&gt;
&lt;li&gt;Missing or Incorrect Headers: Essential headers like authentication tokens not being included.
&lt;/li&gt;
&lt;li&gt;Payload Issues: Malformed JSON or XML payloads causing the server to reject the request.
&lt;/li&gt;
&lt;li&gt;Authentication Failures: Incorrect or expired authentication tokens leading to unauthorized errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Response Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Unexpected Status Codes: Receiving 4xx (client errors) or 5xx (server errors) status codes.
&lt;/li&gt;
&lt;li&gt;Parsing Errors: Invalid JSON or XML responses that can't be parsed by your app.
&lt;/li&gt;
&lt;li&gt;Data Inconsistencies: The data received doesn't match the expected format or contains unexpected values.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Leveraging the Dart DevTools Network Page&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Dart DevTools Network page is a powerful friend in debugging network issues. It provides a comprehensive overview of network requests and responses, allowing you to inspect details such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request and response headers
&lt;/li&gt;
&lt;li&gt;Request and response bodies
&lt;/li&gt;
&lt;li&gt;Timing information (request duration, latency)
&lt;/li&gt;
&lt;li&gt;Status codes
&lt;/li&gt;
&lt;li&gt;Error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8tvcximvb48axyspceh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8tvcximvb48axyspceh.png" alt="Network View" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features and Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Filtering Requests&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filter by URL&lt;/strong&gt;: Focus on specific endpoints by filtering requests containing certain strings.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter by Method&lt;/strong&gt;: Separate GET, POST, PUT, DELETE requests to narrow down your search.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter by Status Code&lt;/strong&gt;: Quickly identify failed requests by filtering status codes (e.g., 4xx, 5xx).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faz6hr10wmb3n06jcfjyo.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faz6hr10wmb3n06jcfjyo.jpeg" alt="Filtering requests" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Inspecting Requests and Responses&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Details&lt;/strong&gt;: Examine the full request, including headers and payload.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Details&lt;/strong&gt;: View the server's response, headers, and body content.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers Inspection&lt;/strong&gt;: Verify if essential headers like Content-Type or Authorization are correctly set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcgd7t0wygdv2dbe05uz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcgd7t0wygdv2dbe05uz.jpeg" alt="Inspecting headers in a request" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Timing Analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Duration&lt;/strong&gt;: Identify slow network calls by looking at the duration of each request.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency Insights&lt;/strong&gt;: Understand network latency issues that might be affecting performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi1ww4ycsry8zfxq856q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi1ww4ycsry8zfxq856q.jpeg" alt="Timing Analysis" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Error Handling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status Codes&lt;/strong&gt;: Quickly spot errors through HTTP status codes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Messages&lt;/strong&gt;: Read detailed error messages returned by the server to understand the root cause.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s03630y93hfjmxlzgj7.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s03630y93hfjmxlzgj7.jpeg" alt="A 404 request" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Example Scenario&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine a situation where an API call is consistently returning a &lt;strong&gt;404 Not Found Error&lt;/strong&gt;. Using the Dart DevTools Network page, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filter Requests&lt;/strong&gt;: Isolate the problematic API call by filtering requests to that specific endpoint.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect the Request&lt;/strong&gt;: Check the request headers and body to ensure everything is correctly formatted.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examine the Response&lt;/strong&gt;: Look at the response body for any error messages or stack traces provided by the server.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze Timing&lt;/strong&gt;: See if the request is taking unusually long, which might indicate server-side performance issues.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust and Retry&lt;/strong&gt;: Based on your findings, make necessary changes and test the request again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s170dysn2fflxr7j25x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s170dysn2fflxr7j25x.jpeg" alt="404 Not Found Error" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Handling async/await and Dart Zones&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Asynchronous operations are at the heart of network calls in Flutter. While async and await make handling asynchronous code more manageable, they can introduce complexities when debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Async/Await Challenges&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Error Handling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unhandled Exceptions&lt;/strong&gt;: Always wrap your async code with try-catch blocks to handle exceptions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future Error Handling&lt;/strong&gt;: When using Future.then(), make sure to include error handling in the onErrorcallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;State Management&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Race Conditions&lt;/strong&gt;: Be cautious of multiple network calls modifying the same state simultaneously.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Updates&lt;/strong&gt;: Ensure that state changes resulting from network calls are properly synchronized with the UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Debugging Techniques&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Breakpoints&lt;/strong&gt;: Set breakpoints inside async functions to step through code execution.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt;: Use print statements or logging packages to output variable values and execution flow.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugger Tools&lt;/strong&gt;: Utilize Flutter DevTools to inspect variables and call stacks during asynchronous operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Dart Zones and Network&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Dart Zones provide a way to track asynchronous operations and handle errors globally.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Understanding Zones&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What Are Zones?&lt;/strong&gt; Zones allow you to intercept and manage code execution in a specific context.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: You can use runZonedGuarded to catch uncaught asynchronous errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Debugging Considerations&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global Error Handling&lt;/strong&gt;: Implement a global error handler to catch errors not caught in try-catch blocks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zone Context&lt;/strong&gt;: Be aware that variables inside a Zone are accessible throughout its scope, which can help with passing data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Debugging HTTP Requests and Responses&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond using DevTools, there are several techniques you can employ to debug network calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Logging&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Print Statements&lt;/strong&gt;: Output request and response data to the console for quick inspection.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging Packages&lt;/strong&gt;: Use packages like logger to manage logging levels and output formats.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;HTTP Libraries Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interceptors&lt;/strong&gt;: If you're using packages like Dio, you can use interceptors to monitor and modify requests and responses.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Leverage built-in error handling mechanisms to catch and process errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt;: Write tests for your network layers to ensure they handle various scenarios correctly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mocking&lt;/strong&gt;: Use mocking frameworks to simulate network responses for different test cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Third-Party Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network Profilers&lt;/strong&gt;: Tools like &lt;a href="https://www.charlesproxy.com" rel="noopener noreferrer"&gt;Charles Proxy&lt;/a&gt; or &lt;a href="https://www.wireshark.org" rel="noopener noreferrer"&gt;Wireshark&lt;/a&gt; can monitor network traffic outside of your app.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Proxies&lt;/strong&gt;: Use proxies to intercept and modify network traffic for testing purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Mastering the art of debugging network calls is essential for building robust and reliable Flutter applications. By effectively using the Dart DevTools Network page, understanding async/await and Dart Zones, and employing additional debugging techniques, you can efficiently identify and resolve network-related issues.&lt;/p&gt;

&lt;p&gt;In this article, we've covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common network-related errors and how to recognize them
&lt;/li&gt;
&lt;li&gt;Leveraging the Dart DevTools Network page to inspect network traffic
&lt;/li&gt;
&lt;li&gt;Handling asynchronous code and Dart Zones in network operations
&lt;/li&gt;
&lt;li&gt;Debugging techniques for HTTP requests and responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these strategies into your development workflow, you'll be better equipped to tackle any network challenges that come your way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for the next part of this series, where we'll delve into debugging UI performance issues in Flutter!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions or need further assistance, feel free to reach out. I'm always here to help!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Connect with me on &lt;a href="https://twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;X(formerly Twitter)&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/david-adegoke/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; for more Flutter tips and tutorials.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>debugging</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Introduction to the World of Debugging(Part One)</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Sun, 27 Jul 2025 04:23:40 +0000</pubDate>
      <link>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-one-1hjh</link>
      <guid>https://dev.to/blazebrain/mastering-the-art-of-debugging-in-flutter-part-one-1hjh</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;"If debugging is the process of removing bugs, then programming must be the process of putting them in." — Edsger W. Dijkstra&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Oh boy, Edsger definitely knew what he was saying, because what?!&lt;/p&gt;

&lt;p&gt;We've all been there, or better still, I've been there... a lot. You're building a piece of software etc, everything is going smoothly, and then ...bam! Your software crashes unexpectedly or starts behaving in ways you never intended. Red lines flood your console, and after multiple attempts to understand, you start feeling a wide range of emotions, from frustration to exhaustion, sometimes hunger :). I mean, why won't this thing just work?! What do I have to do?!&lt;/p&gt;

&lt;p&gt;Frustrating yeah? That's exactly why debugging is an essential skill for any developer, and it's no different in the world of Flutter and Dart. It's not just about fixing errors; it's about ensuring that your application runs smoothly and maintains high quality.&lt;/p&gt;

&lt;p&gt;In this article, the first in our series on the art of debugging, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What debugging is
&lt;/li&gt;
&lt;li&gt;The importance of debugging in programming
&lt;/li&gt;
&lt;li&gt;Common types of errors developers face
&lt;/li&gt;
&lt;li&gt;An introduction to a powerful Flutter debugging tool: Flutter DevTools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ready to dive in? Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Is Debugging?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Debugging is the process of identifying, isolating, and fixing errors (or "bugs") in your codebase. It's a critical part of software development that ensures your application behaves as expected and delivers a great user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Importance of Debugging in Programming&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Debugging is vital for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improved Code Quality: By finding and fixing errors, we create more robust and reliable applications.
&lt;/li&gt;
&lt;li&gt;Enhanced Performance: Resolving performance bottlenecks during debugging ensures our apps run efficiently.
&lt;/li&gt;
&lt;li&gt;Deeper Understanding of Code: Debugging helps us gain insights into how our code works, leading to better programming practices.
&lt;/li&gt;
&lt;li&gt;Better User Experience: An application free from bugs provides users with a smooth and satisfying experience.&lt;/li&gt;
&lt;li&gt;Reduced Development Time: Catching and fixing errors early can save time and resources in the long run.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Common Errors in Programming&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As Engineers, we might encounter different kinds of errors during development. Recognizing and understanding these errors is the first step toward effective debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Syntax Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These occur when we violate the syntax rules of the programming language. For example, missing quotes in strings or forgetting a semicolon. In Dart, these errors are usually caught by the analyzer before the code runs. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing quotes in strings - String name = John; instead of String name = "John";&lt;/li&gt;
&lt;li&gt;Forgetting semicolons - int x = 5 instead of int x = 5;&lt;/li&gt;
&lt;li&gt;Missing parentheses - if x == 5 instead of if (x == 5)&lt;/li&gt;
&lt;li&gt;Unmatched braces - { without corresponding }&lt;/li&gt;
&lt;li&gt;Invalid keywords - funtion instead of function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhg0zglbl0lp014moioh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhg0zglbl0lp014moioh5.png" alt="Syntax Error Example" width="800" height="467"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Syntax Error Example&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Runtime Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Runtime errors happen during the execution of the code. They can also be called exceptions in Dart. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FormatException - when trying to parse invalid data formats&lt;/li&gt;
&lt;li&gt;Null pointer/null reference errors - when accessing properties on null objects&lt;/li&gt;
&lt;li&gt;Array index out of bounds - when accessing invalid array indices,. like trying to fetch item 8 in an array with length 5.&lt;/li&gt;
&lt;li&gt;File not found - when trying to access non-existent files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8y7mer78eeta4j46fn9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8y7mer78eeta4j46fn9j.png" alt="Runtime Error Example" width="800" height="665"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Runtime Error Example&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Compilation Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Compilation errors prevent the high-level language code from being converted into machine code. These are caught before the program runs and often result from type mismatches or missing imports.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;int x = "hello"; (type mismatch)&lt;/li&gt;
&lt;li&gt;if (x == 5 { (missing closing parenthesis)&lt;/li&gt;
&lt;li&gt;y = x + 1; where x is not declared (undefined variable)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jon4shla4tbw28lp4gc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jon4shla4tbw28lp4gc.png" alt="Compilation Error Example" width="800" height="537"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Compilation Error Example&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Logic Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Logic errors are tricky, they don't prevent your program from running, but they cause it to produce incorrect results. This happens when there's a flaw in your algorithm or incorrect implementation due to a misunderstanding of the problem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a multiplication operator * instead of addition + when calculating a sum.
&lt;/li&gt;
&lt;li&gt;Infinite loops due to incorrect loop conditions&lt;/li&gt;
&lt;li&gt;Incorrect sorting algorithms&lt;/li&gt;
&lt;li&gt;Wrong mathematical formulas&lt;/li&gt;
&lt;li&gt;Misunderstanding of data relationships&lt;/li&gt;
&lt;li&gt;Incorrect boolean logic (using AND instead of OR, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnudpkz6mc8843igass5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnudpkz6mc8843igass5x.png" alt="Logic Error Example" width="800" height="409"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Logic Error Example&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Semantic Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Semantic errors occur when the code doesn't do what it's supposed to, even though it's syntactically correct. It's about meaning rather than syntax. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using - instead of + when you intended to add two numbers. &lt;/li&gt;
&lt;li&gt;Using = (assignment) instead of == (equality comparison)&lt;/li&gt;
&lt;li&gt;Using the wrong variable name&lt;/li&gt;
&lt;li&gt;Calling a function with parameters in the wrong order&lt;/li&gt;
&lt;li&gt;Using integer division when you need floating-point division&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2tg0mtm1jyln7s7t721.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2tg0mtm1jyln7s7t721.png" alt="Semantic Error Example" width="800" height="513"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Semantic Error Example&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction to Flutter &amp;amp; Dart DevTools&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What Are DevTools?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Flutter DevTools is a suite of performance and debugging tools for Flutter and Dart applications. They help you visualize your widget tree, debug layouts, analyze performance, and much more.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Launching DevTools in Visual Studio Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To access DevTools in VS Code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Press F1 to open the command palette.
&lt;/li&gt;
&lt;li&gt;Ensure your debug session is active.
&lt;/li&gt;
&lt;li&gt;Type "Open DevTools" and select any of the available commands.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpwqg9p5nxfj5t9tlgii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpwqg9p5nxfj5t9tlgii.png" alt="Flutter DevTools" width="512" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exploring the Features of Flutter DevTools&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Flutter DevTools offers a range of powerful tools to help you debug and optimize your applications. Let's explore some of them:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Flutter Inspector&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Flutter Inspector allows you to visualize and explore your widget tree in real-time. It's invaluable for understanding existing layouts and diagnosing layout issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5oe2424zdwmymdp22lrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5oe2424zdwmymdp22lrg.png" alt="Flutter Inspector View" width="512" height="196"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Flutter Inspector View&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Performance View&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Performance view helps you diagnose performance problems and UI jank (lagging animations or interactions) in your application. It includes tools like the Flutter frames chart, which shows frame rendering times.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqua4vsus9yq12zve8xgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqua4vsus9yq12zve8xgl.png" alt="Flutter Frames Chart" width="512" height="68"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Flutter Frames Chart&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. CPU Profiler&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The CPU Profiler allows you to record and analyze CPU activity in your app. It's useful for identifying performance bottlenecks and optimizing CPU usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Memory View&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Memory view provides insights into your app's memory allocation. You can detect memory leaks, analyze memory usage, and optimize accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Debug Console&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Debug Console lets you watch your app's standard output, evaluate expressions, and analyze object references while your app is running or paused in debug mode.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F343zwmgaqiyq5hytjjtf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F343zwmgaqiyq5hytjjtf.png" alt="Debug Console View" width="512" height="174"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Debug Console View&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Network View&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Network view allows you to inspect HTTP, HTTPS, and WebSocket traffic from your app. It's helpful for debugging network requests and responses.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzs6mt77afgn50du8k9b4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzs6mt77afgn50du8k9b4.png" alt="Network View" width="512" height="325"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Network View&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Network traffic recording starts automatically when the Network page is opened. If it's not recording, click the Resume button in the upper left corner.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7. Debugger&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Debugger is a full source-level debugger that supports breakpoints, stepping (into, over, out), and variable inspection.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyvmwdeyvizuo6p243n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyvmwdeyvizuo6p243n.png" alt="Debugger View" width="512" height="326"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Debugger View&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;8. Logging View&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Logging view displays events from the Dart runtime, Flutter framework, and application-level logging events. It's useful for tracking the flow of your app and identifying issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lrby3rikhnnjfsea9xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lrby3rikhnnjfsea9xo.png" alt="Logging View" width="512" height="221"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Logging View&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;9. App Size Tool&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The App Size tool allows you to analyze the total size of your app, helping you optimize for download size and storage space.&lt;/p&gt;

&lt;p&gt;To access the App Size tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure DevTools is connected to a running application.
&lt;/li&gt;
&lt;li&gt;Navigate to the "App Size" tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Phewww&lt;/em&gt;, that was a lot yeah? Let's do a quick recap. We did an introduction to debugging, touched on how understanding and effectively using debugging tools is crucial for any Flutter Engineer. Always remember, debugging isn't just about fixing errors—it's about improving code quality, enhancing performance, and providing a better user experience.&lt;/p&gt;

&lt;p&gt;In this first part of our series on the art of debugging, we've covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The definition and importance of debugging
&lt;/li&gt;
&lt;li&gt;Common types of errors in programming
&lt;/li&gt;
&lt;li&gt;An introduction to Flutter DevTools and its powerful features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the upcoming articles, we'll dive deeper into specific debugging techniques, explore more features of Flutter DevTools, and learn how to tackle complex bugs in your Flutter applications.&lt;/p&gt;

&lt;p&gt;Stay tuned, and happy coding!&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you have any questions or need further assistance. I'm always here to help!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or connect with me on &lt;a href="https://www.linkedin.com/in/david-adegoke" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; for more Flutter tips and tutorials.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>debugging</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Design Patterns - Flutter</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Thu, 23 Jun 2022 08:41:12 +0000</pubDate>
      <link>https://dev.to/blazebrain/design-patterns-flutter-9dh</link>
      <guid>https://dev.to/blazebrain/design-patterns-flutter-9dh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Across diverse languages and frameworks, some tested and trusted sets of steps/procedures have solved problems in the software world. These processes form the core of many solutions to specific issues. On their own, they are not the solutions to these particular problems, but they form the core upon which various solutions lies upon. These set of steps/patterns are what we refer to as &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;Design Patterns&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are Design Patterns?
&lt;/h2&gt;

&lt;p&gt;Design patterns are a series of patterns that provides a template or description of how you can solve a common problem. On their own, they are not complete solutions to problems but instead offer an explanation or way to solve a general re-occurring problem in the world of software design. &lt;/p&gt;

&lt;p&gt;As a result of the similarities between issues raised, there was a need for a unified way of solving these common problems. That was what brought up the initial set of design patterns. You might have applied many of these solutions while developing a product(well yeah!). They are solutions that go deep into software development and tend to solve core problems without restricting them to a language or framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of Design Patterns
&lt;/h2&gt;

&lt;p&gt;Design patterns provide you with lots of benefits, some of which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Providing a general standard for communication among developers.&lt;/li&gt;
&lt;li&gt;Reducing development time and speeding up the development process.&lt;/li&gt;
&lt;li&gt;Providing proven solutions to common re-occurring problems.&lt;/li&gt;
&lt;li&gt;Provides best practices to get a clean reusable, and bug-free codebase.&lt;/li&gt;
&lt;li&gt;Providing a core/foundation upon which you can build solutions to re-occurring issues in software design
## Gang Of Four Design Patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are a set of design patterns proposed by four authors: &lt;a href="https://en.wikipedia.org/wiki/Erich_Gamma" rel="noopener noreferrer"&gt;Erich Gamma&lt;/a&gt;, Richard Helm, &lt;a href="https://en.wikipedia.org/wiki/Ralph_Johnson_(computer_scientist)" rel="noopener noreferrer"&gt;Ralph Johnson&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/John_Vlissides" rel="noopener noreferrer"&gt;John Vlissides&lt;/a&gt;. They are most often referred to as the Gang of Four. They wrote a book titled &lt;a href="https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0201633612&amp;amp;linkCode=as2&amp;amp;tag=triatcraft-20&amp;amp;linkId=XRGUDJCGWC6AJNZM" rel="noopener noreferrer"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, which introduces the design patterns and gives more information on each. This book was a significant aid for the Software Development world as it tackles many of these problems and how these patterns intend to solve them. There are 23 design patterns proposed in the book, which is divided into three categories&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structural &lt;/li&gt;
&lt;li&gt;Behavioural and&lt;/li&gt;
&lt;li&gt;Creational.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will discuss more on each of these categories in the next section. Note that the "Design" here does not refer to UiUx Designs but is more about the design and development of software. One significant benefit of Design Patterns is that it's not specific to a particular language/framework but can be developed and implemented/used across various programming languages. &lt;/p&gt;

&lt;h2&gt;
  
  
  Categories of Design Patterns
&lt;/h2&gt;

&lt;p&gt;We would look into each design pattern and why they are grouped into these categories. Each of these categories deals with a particular use case, and the patterns under them revolve around the solutions to similar situations in development. Since we can't go deep into each of the 23 design patterns, I have included links to study further each of these patterns and how they can be applied in Flutter. In future articles also, we would go deep into specific design patterns and walk through their implementations using Flutter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creational Design Patterns
&lt;/h2&gt;

&lt;p&gt;These are the design patterns that deal with the way Classes and Objects are created/instantiated. There are five design patterns in the Creational Design Pattern category. They are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-11-abstract-factory-7098112925d8" rel="noopener noreferrer"&gt;Abstract Factory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-10-factory-method-c53ad11d863f" rel="noopener noreferrer"&gt;Factory&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-18-builder-cdc90b222724" rel="noopener noreferrer"&gt;Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-14-prototype-7d7d18bcf643" rel="noopener noreferrer"&gt;Prototype&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-1-singleton-437f04e923ce" rel="noopener noreferrer"&gt;Singleton&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structural Design Patterns
&lt;/h2&gt;

&lt;p&gt;These are design patterns that deals with the way Classes and Objects get composed. It deals with the way objects combine to achieve the desired result. There are seven design patterns under this category, and they include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-2-adapter-3f05c02a7c84" rel="noopener noreferrer"&gt;Adapter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-17-bridge-b31711b629f2" rel="noopener noreferrer"&gt;Bridge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-4-composite-23473cccf2b3" rel="noopener noreferrer"&gt;Composite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-16-decorator-bf0dd711f093" rel="noopener noreferrer"&gt;Decorator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-7-facade-eb40434fb973" rel="noopener noreferrer"&gt;Facade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-19-flyweight-3d41cfdf36c" rel="noopener noreferrer"&gt;Flyweight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-15-proxy-af8743b24269" rel="noopener noreferrer"&gt;Proxy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Behavioural Design Patterns
&lt;/h2&gt;

&lt;p&gt;These are design patterns that deal with how Objects communicate with one another. There are 11 design patterns in this category. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-20-chain-of-responsibility-2ff122624297" rel="noopener noreferrer"&gt;Chain of Responsibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-12-command-e199172e16eb" rel="noopener noreferrer"&gt;Command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-8-interpreter-8f15e9de3ee9" rel="noopener noreferrer"&gt;Interpreter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-9-iterator-8da27ee83c17" rel="noopener noreferrer"&gt;Iterator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-22-mediator-575e7aa6bfa9" rel="noopener noreferrer"&gt;Mediator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-13-memento-b487769cf104" rel="noopener noreferrer"&gt;Memento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-23-observer-1e1b0ea81d73" rel="noopener noreferrer"&gt;Observer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-6-state-be06cb05525c" rel="noopener noreferrer"&gt;State&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-5-strategy-ef9cf5b5b694" rel="noopener noreferrer"&gt;Strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-3-template-method-89799d84e378" rel="noopener noreferrer"&gt;Template method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mkobuolys.medium.com/flutter-design-patterns-21-visitor-af5def0699be" rel="noopener noreferrer"&gt;Visitor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these terms may/may not be familiar; you probably might have noticed a few that you have used while developing before; these guides would give you a better understanding of why they are used and what they solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, these patterns offer solutions to typical and re-occurring software design and development problems. They do not depend on a particular language/framework. However, they do not present immediate solutions to those problems; they serve as a basis/ground upon which you can build solutions to these problems. A deep understanding of these patterns would impact the quality of your codes and enhance communication between you and other developers. &lt;/p&gt;

&lt;p&gt;If you have any questions about any of them or questions on Flutter, you can&lt;br&gt;
reach me through on any of the platforms listed &lt;a href="https://linktr.ee/blazebrain" rel="noopener noreferrer"&gt;here&lt;/a&gt;. I would be glad to answer. Cheers!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>architecture</category>
      <category>programming</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a Reminder App with Local Notifications using WorkManager API</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Sat, 26 Feb 2022 20:52:40 +0000</pubDate>
      <link>https://dev.to/blazebrain/building-a-reminder-app-with-local-notifications-using-workmanager-api-385f</link>
      <guid>https://dev.to/blazebrain/building-a-reminder-app-with-local-notifications-using-workmanager-api-385f</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pause, tap your feet, scratch your hair a few times, squeeze your face a bit, then after a few choice seconds, voila, you remember, you finally yanked it off its hiding place. That piece of information, you eventually remember it! Sounds familiar? That’s what happens to many people daily across the entire continent. With the number of things we engage in, we tend to forget one or two pieces of information and then go through the scenario above, over and over. Well, mobile apps and technologies like Kotlin to the rescue. With the use of reminder applications, we can remind ourselves of essential/crucial events we must attend to; through notifications that pop up and draw our attention, we can adequately plan the day and be more productive.&lt;/p&gt;

&lt;p&gt;In this article, we would build a Reminder app from scratch, cool yeah? You would learn to build a Reminder Application that uses Local Notifications to display reminders of events you have previously set. You would be able to set a message to display and select a Date and Time for the reminder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technologies to be used
&lt;/h2&gt;

&lt;p&gt;As this tutorial will be hands-on, there are a few technologies that you must have and be familiar with.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kotlin Programming Language&lt;/li&gt;
&lt;li&gt;Android Studio&lt;/li&gt;
&lt;li&gt;Basic Layout in Android Development&lt;/li&gt;
&lt;li&gt;WorkManager API( we will discuss more of this in the next section).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is WorkManager API?
&lt;/h2&gt;

&lt;p&gt;WorkManager API is an API used to create scheduled notifications, i.e. pop-up messages that have been planned on the background process and delivered at a particular time. WorkManager makes it easy to schedule tasks to run even if the application exits or restarts. This means that our notifications would be delivered even if we closed the app. We would go through the step by step process of integrating the API into our app and using it to create a Reminder Application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s get practical
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;We’ll start by creating a new project in Android Studio. Select the Empty Activity Option, give the project a name of your choosing and then click ‘Finish’. Android Studio would create the basic structure, which we would build on as we proceed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq8rn3yg6n6tkra3otj3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq8rn3yg6n6tkra3otj3j.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q33d5771rd9rb6ibnk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7q33d5771rd9rb6ibnk1.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswdjbjfxf45xoxihm0in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswdjbjfxf45xoxihm0in.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are set to begin the actual coding; we would start from bottom to top, i.e., logic before layout or user interface.&lt;/p&gt;

&lt;p&gt;The first thing we’ll do is create a folder named &lt;code&gt;utils&lt;/code&gt;; this folder would contain all the helper classes we would be making use of in the application.&lt;/p&gt;

&lt;p&gt;Right-click on the package-name folder for your app and select New to create a new file. Select Kotlin Class/File and name it &lt;code&gt;NotificationHelper&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the NotificationHelper
&lt;/h3&gt;

&lt;p&gt;The NotificationHelper class is the class that would handle all functionalities relating to notifications with the application.&lt;/p&gt;

&lt;p&gt;We would pass in the context also as we would need it later on.&lt;/p&gt;

&lt;p&gt;In this class, we’ll create two private variables&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;channelId&lt;/code&gt; to identify our notifications channel and&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;notificationId&lt;/code&gt; to identify the notifications could be a random integer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll be implementing the BigPicture NotificationStyle in our notifications, which means that our notifications would contain images and the reminder text. For this we would need two images. Grab two images from the internet or your local device. Drag and drop it into the &lt;code&gt;drawable&lt;/code&gt; folder of the res package. Import normally and also for v24. I have two images, &lt;code&gt;checklist.png&lt;/code&gt; and &lt;code&gt;reminder_char.png.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabbx6mgctn3dnyoi2r13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabbx6mgctn3dnyoi2r13.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0bkfzouo99tez6u8jf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0bkfzouo99tez6u8jf3.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will create a private function responsible for creating a notifications channel through which the NotificationManager would deliver our reminders. For that, we would need to check if the user's phone is Android version Oreo and above; this is because we don’t need to create a notification channel for older versions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CHANNEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CHANNEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IMPORTANCE_DEFAULT&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Reminder Channel Description"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notificationManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NOTIFICATION_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;
            &lt;span class="n"&gt;notificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After checking, we create a notification channel using the &lt;code&gt;channelID&lt;/code&gt; we declared earlier. We also set the Notification Priority to default and set the description of our Notification channel. After this, we call context and access the NotificationService of the device and use it to create a Notifications Channel. With this, we’ve set up the function to create notification Channels.&lt;/p&gt;

&lt;p&gt;Next, we create a function to &lt;code&gt;createNotifications&lt;/code&gt;. This makes it easy to reuse in other parts of our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// 1      &lt;/span&gt;
    &lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLAG_ACTIVITY_NEW_TASK&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLAG_ACTIVITY_CLEAR_TASK&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BitmapFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reminder_char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 5&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notification&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CHANNEL_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSmallIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checklist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLargeIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BigPictureStyle&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;bigPicture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bigLargeIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pendingIntent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PRIORITY_DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;// 6&lt;/span&gt;
    &lt;span class="nc"&gt;NotificationManagerCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NOTIFICATION_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; - Call the &lt;code&gt;createNotificationChannel&lt;/code&gt; function created above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; - Create an &lt;code&gt;Intent&lt;/code&gt; that calls the &lt;code&gt;MainActivity&lt;/code&gt; when it runs. Adding an intent is to start up the app when the user clicks on the notification in the menu tray.&lt;/p&gt;

&lt;p&gt;We also add flags to the intent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Intent.FLAG_ACTIVITY_NEW_TASK&lt;/code&gt; will ensure the &lt;code&gt;MainActivity&lt;/code&gt; opens up as a new Task on the history stack. It comes up as the root and appears as new in the history stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Intent.FLAG_ACTIVITY_CLEAR_TASK&lt;/code&gt; will cause any existing task associated with the activity to clear out before the activity starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; - Since we are not launching the intent immediately, create a pending intent and pass the intent created to it. &lt;code&gt;PendingIntent&lt;/code&gt; in itself is a description of an Intent and what action it’s to perform. It gives an external application(like NotificationManager in our case)access to launch tasks for us as if we were launching them now, with the same set of permissions we would use. We call &lt;code&gt;getActivity&lt;/code&gt;, which means the PendingIntent is to start a newActivity when it launches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; - We go-ahead to create an icon for the notification using a &lt;code&gt;BitmapFactory&lt;/code&gt;. We have already imported the images we want to use earlier, so we call &lt;code&gt;decodeResource&lt;/code&gt; on BitmapFactory and then pass the image we want to use. We would use the icon in the notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; - Next, we create the notification object by using &lt;code&gt;NotificationCompat.Builder&lt;/code&gt; and pass in the channelID. We go-ahead to set other configurations for our notifications like &lt;code&gt;smallIcon&lt;/code&gt;, &lt;code&gt;largeIcon&lt;/code&gt;, message(which will come from the message parameter goes into this function), the &lt;code&gt;notificationStyle&lt;/code&gt;(we’ll be using the &lt;code&gt;BigPictureStyle&lt;/code&gt;), we also pass in the icon we created in step 4. We also set the &lt;code&gt;contentIntent&lt;/code&gt;(the pendingIntent we created in step 3) and then the &lt;code&gt;notificationPriority&lt;/code&gt;(pass it as default). Lastly, we call build to add all these configurations as part of the object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; - We create the notification using the &lt;code&gt;NotifcationManagerCompat&lt;/code&gt;, passing in the NotificationID and the notification Object we created in Step 5.&lt;/p&gt;

&lt;p&gt;With this, our NotificationHelper class is good to go, and we can start triggering “instant” notifications by simply calling the &lt;code&gt;createNotifcation&lt;/code&gt; function, passing in the title and description, and getting a notification.&lt;/p&gt;

&lt;p&gt;However, this does not fulfill our aim as we want the notifications to pop up at a time we set, not instantly, i.e. we want a delayed notification. This is where WorkManager API comes in; using this API; we would be able to create a notification that would come up when we want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating the WorkManager API
&lt;/h3&gt;

&lt;p&gt;To access the WorkManager API, we need to add it as a dependency. Open your build.gradle file in the GradleScripts section and add the work manager API there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// other dependencies here&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.work:work-runtime-ktx:2.5.0"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forget to &lt;strong&gt;sync&lt;/strong&gt; after adding this.&lt;/p&gt;

&lt;p&gt;Next, we create a &lt;code&gt;Worker&lt;/code&gt; class named &lt;code&gt;ReminderWorker&lt;/code&gt; in the utils package. This class would inherit from the Worker class coming from the WorkManager API and give us access to a function &lt;code&gt;doWork()&lt;/code&gt;. This async function, which we will override in our class, would be responsible for calling the &lt;code&gt;createNotification&lt;/code&gt; function, defined in NotificationHelper. and creating the Notification. The ReminderWorker class takes in two parameters, the &lt;code&gt;context&lt;/code&gt; and the &lt;code&gt;WorkerParameters&lt;/code&gt;, which it would pass over to its Superclass.&lt;/p&gt;

&lt;p&gt;Ok, let’s pause there and see how it looks in the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReminderWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WorkerParameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;NotificationHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we want to be able to pass in our title and message for each Notification, we use the &lt;code&gt;inputData&lt;/code&gt; object, which is a key-value object that contains information that needs to be processed, in our case here, the title and object information that needs to be processed in the &lt;code&gt;doWork&lt;/code&gt; function. Finally, we return the result as a success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a WorkRequest
&lt;/h3&gt;

&lt;p&gt;A WorkRequest is an object which contains all the information the WorkManager needs to schedule and run your work. It takes in a &lt;code&gt;WorkerClass&lt;/code&gt; that has defined the work to be done. There are two of WorkRequests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OneTimeWorkRequest: A WorkRequest which triggers only once.&lt;/li&gt;
&lt;li&gt;PeriodicWorkRequest: A WorkRequest which runs periodically based on set configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we want our notifications to display only once, i.e. it should only remind us at the time and date we set, we would use the OneTimeWorkRequest.&lt;/p&gt;

&lt;p&gt;To start with this, open up your &lt;code&gt;MainActivity.kt&lt;/code&gt; file; it contains an empty activity class with the contentView set to the &lt;code&gt;activity_main.xml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a private function in the&lt;code&gt;MainActivity&lt;/code&gt; called &lt;code&gt;createWorkRequest&lt;/code&gt;. This function takes in a message, the note we want to add to the notifications. In this function, we create a WorkRequest object by calling the &lt;code&gt;OneTimeRequestBuilder&lt;/code&gt; and passing the ReminderWorker class.&lt;br&gt;
We set configurations like &lt;code&gt;initialDelay&lt;/code&gt;. The OneTimeWorkRequest allows us to delay the time before the task(our notification) displays. We can set the delay to milliseconds, seconds, minutes, hours etc. For our reminder app, we want to hold our notification until the actual time and day we selected. To do that, we calculate the difference between the DateTime the user selected and the &lt;code&gt;currentDateTime&lt;/code&gt;. We would then pass this delay when setting the &lt;code&gt;intialDelay&lt;/code&gt; for the workRequest. We would go through each step while setting up the rest of the &lt;code&gt;MainActivity&lt;/code&gt; class.&lt;br&gt;
We also set the &lt;code&gt;InputData&lt;/code&gt; through the &lt;code&gt;workDataOf&lt;/code&gt; object, passing a map of the values we want to use in our notifications. We would pass in the message through the message parameter for this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createWorkRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timeDelayInSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;myWorkRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OneTimeWorkRequestBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReminderWorker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInitialDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeDelayInSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInputData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;workDataOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"Reminder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nc"&gt;WorkManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myWorkRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we call the WorkManager, get an instance and enqueue the request. With this, we are set! You’ve done well getting to this point. Now let’s go over and create a layout to link it up and see our Reminder App in its full beauty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laying out the View
&lt;/h3&gt;

&lt;p&gt;We would set up a simple interface that would include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An EditText:&lt;/strong&gt; to input the message you want to show in the notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A TimePicker:&lt;/strong&gt; to select the time of the day you wish to show your notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A DatePicker:&lt;/strong&gt; to choose the day you want the reminder to come up&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Button:&lt;/strong&gt; to set the notification with all the parameters specified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open up your res &amp;gt; layout &amp;gt; activity_main.xml file. We would use the Linear Layout and add each of those components listed above, giving them unique ids that would be used to reference them in the &lt;code&gt;MainActivity&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;androidx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constraintlayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConstraintLayout&lt;/span&gt; &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ScrollView&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_constraintBottom_toBottomOf&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_constraintEnd_toEndOf&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_constraintStart_toStartOf&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_constraintTop_toTopOf&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
    &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LinearLayout&lt;/span&gt; &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
        &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
        &lt;span class="n"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
        &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;
        &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;orientation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"vertical"&lt;/span&gt;
        &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gravity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
        &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"10dp"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EditText&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@+id/editText"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Message"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DatePicker&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@+id/datePicker"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;datePickerMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"spinner"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;calendarViewShown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimePicker&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@+id/timePicker"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_marginTop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"20dp"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_marginLeft&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"19dp"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;timePickerMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"spinner"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;
                &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@+id/setBtn"&lt;/span&gt;
                &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
                &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;layout_height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
                &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"SET"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;LinearLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ScrollView&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;androidx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constraintlayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConstraintLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we head over to the &lt;code&gt;MainActivity.kt&lt;/code&gt; file and start making use of each of these components to set up our notifications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;chosenYear&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;chosenMonth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;chosenDay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;chosenHour&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;chosenMin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;descriptionText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EditText&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;editText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;button&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setBtn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;datePicker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DatePicker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datePicker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;timePicker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimePicker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timePicker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;today&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
        &lt;span class="n"&gt;datePicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DAY_OF_MONTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;chosenYear&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;
            &lt;span class="n"&gt;chosenMonth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;
            &lt;span class="n"&gt;chosenDay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// 4&lt;/span&gt;
        &lt;span class="n"&gt;timePicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnTimeChangedListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;chosenHour&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt;
            &lt;span class="n"&gt;chosenMin&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// 5&lt;/span&gt;
        &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// 6 Get the DateTime the user selected&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userSelectedDateTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;userSelectedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chosenYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chosenMonth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chosenDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chosenHour&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chosenMin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;// 7 Next get DateTime for today&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;todayDateTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

       &lt;span class="c1"&gt;// 8&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;delayInSeconds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSelectedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeInMillis&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todayDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeInMillis&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="c1"&gt;// 9&lt;/span&gt;
            &lt;span class="nf"&gt;createWorkRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;descriptionText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;delayInSeconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="c1"&gt;// 10     &lt;/span&gt;
        &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Reminder set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; - We create variables to hold the year, month, day, hour and minute that the user selects for the notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; - We reference View components using their IDs, using the &lt;code&gt;findViewById&lt;/code&gt; function. We do this for each component, the EditText, the Button, the DatePicker and the TimePicker. We also get the current DateTime by getting an Instance of Calendar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; - We initialize the datePicker and assign the current year, month and day to it, so when the Calendar comes up, it starts from the current day and not well, from Feb 24, 1927. After initializing, we pass the values selected by the user to the variables we created in Step 1 for a year, month and day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; - We call &lt;code&gt;setOnTimeChangeListener&lt;/code&gt; on the TimePicker and then set the hour and minute the user selected to the variables we declared in Step 1 whenever the user interacts with the TimePicker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; - We call &lt;code&gt;setOnClickListener&lt;/code&gt; on the Button to run our logic when the user clicks the “Set” button in the View.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; - Using the year, month, day, hour and minute that the user selected, we set an instance of Calendar. we save this instance to a variable&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; - We get an instance of Calendar to give us the current day DateTime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt; - We convert the &lt;code&gt;userSelectedDateTime&lt;/code&gt; and &lt;code&gt;todayDateTime&lt;/code&gt; to milliseconds. After this, we divide them by 1000L, converting them to seconds. Finally, we subtract &lt;code&gt;todayDateTime&lt;/code&gt; from the &lt;code&gt;userSelectedDateTime&lt;/code&gt; to get the number of seconds the notification would delay before it displays to the user. We save the result to a variable, &lt;code&gt;delayInSeconds&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9&lt;/strong&gt; - We call the &lt;code&gt;createWorkRequest&lt;/code&gt; function and pass in the message from the descriptionText View component and the &lt;code&gt;delayInSeconds&lt;/code&gt; to it, creating the workRequest for the notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10&lt;/strong&gt; - We display a toast message informing the user that the Reminder is set.&lt;/p&gt;

&lt;p&gt;With this done, let’s run our code and test it out.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/C7t1Wd1gLTw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And there you go, we have a full-fledged Reminder Application with Local Notification, built using the WorkManager API in Kotlin. You can checkout the source code for the app &lt;a href="https://github.com/Blazebrain/reminder_app" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hurray! You got here; give yourself a round of applause; you deserve it! You’ve mastered displaying Local Notifications in An Android App using the WorkManager API. You’ve also built a simple app you can use personally to set reminders, cool yeah? Definitely! If you encounter any issue or want further clarifications, drop a comment below, reach out to me on &lt;a href="https://twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://linkedin.com/in/david-adegoke" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, I would be glad to assist. Do have a pleasant day.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Integrating FaunaDB with Flutter</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Sat, 04 Dec 2021 09:41:17 +0000</pubDate>
      <link>https://dev.to/blazebrain/integrating-faunadb-with-flutter-40cd</link>
      <guid>https://dev.to/blazebrain/integrating-faunadb-with-flutter-40cd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In building mobile apps, especially with an emphasis on scalability, many factors are considered before the development process starts. One of these factors is the way data is stored. We would at a unique solution to managing data in our application, it's called &lt;a href="https://fauna.com/?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_FaunaFFlutter_DAdegoke" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt;. Fauna offers a free, ready to use database that can be setup and ready to go in few minutes(yes, it’s that easy to use). With Fauna, yoiu never need to worry about complex setups or difficult to use queries. They are very relatable and easily understandable. This article will teach you how to integrate and use the Fauna in our Flutter app through a step-by-step procedure. &lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with Flutter.
&lt;/h2&gt;

&lt;p&gt;We would be building a Todo list app with &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; and Fauna. The app would have functionalities including getting all todos, creating new todos, and deleting todos. &lt;/p&gt;

&lt;p&gt;First, head over to create the &lt;a href="https://fauna.com?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_FaunaFFlutter_DAdegoke" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; website and create an account.&lt;/p&gt;

&lt;p&gt;After successful signup and login, on the dashboard screen. Click the Create Database button to create a new database. We would name our database “todo”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevsahiduodxej92xdh45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevsahiduodxej92xdh45.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the database, click on Security → New Key. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvutsspsev46bz81v0lo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvutsspsev46bz81v0lo.png" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is to generate a key that the app would use to access the database. It's the link between our app and Fauna. Make sure you copy the link to a secure place as it is only displayed once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh0yds35jrzutycqlvpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh0yds35jrzutycqlvpv.png" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, create the collection by clicking the Collections tab at the left. Click the New Collection button and enter the name of the collection. We can call ours “todos”, just like the database it’s in, because we’re only using one collection here. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F053bd41nxqjgxxq2nzea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F053bd41nxqjgxxq2nzea.png" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next on the list is to create an index. This is a more straightforward and speedy way of sorting through the data in the database without extra stress (yeah! Fauna is sweet). Click the Indexes tab, then the New Index button. For this particular index, we would name it “all_todos” because we want it to do just that: return the complete list of todos we have stored. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjm4tsta60bx1d7jqlpi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjm4tsta60bx1d7jqlpi4.png" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that, we've set up things on the Fauna side, so now it’s on to our codebase.&lt;/p&gt;

&lt;p&gt;Create a new flutter project using the “flutter” command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`flutter create faunadb_sample_project`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once done, go to the pubspec.yaml file and start by adding the dependencies. In the dependencies block, add the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://pub.dev/packages/faunadb_data" rel="noopener noreferrer"&gt;faunadb_data&lt;/a&gt; : This will be the link between our application and the FaunaDB. Using this package, we will be able to perform CRUD operations on our database.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://pub.dev/packages/stacked" rel="noopener noreferrer"&gt;stacked&lt;/a&gt;: The architectural solution we’ll use in the application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/stacked_services" rel="noopener noreferrer"&gt;stacked services&lt;/a&gt;: A set of ready-made services offered by stacked, which can be customized.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/intl" rel="noopener noreferrer"&gt;intl&lt;/a&gt;: For internationalization, number formatting, and some other things. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/optional" rel="noopener noreferrer"&gt;optional&lt;/a&gt; : This ensures that our functions don’t return null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under dev_dependencies, add &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/build_runner" rel="noopener noreferrer"&gt;build_runner&lt;/a&gt; : This give us access to run commands to generate files needed in the app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/stacked_generator" rel="noopener noreferrer"&gt;stacked generator&lt;/a&gt;: This enables auto generating files  marked with the Stacked Annotations.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    dependencies:
     cupertino_icons: ^1.0.2
     faunadb_data: ^0.0.6
     flutter:
      sdk: flutter
     intl: ^0.17.0
     optional: ^6.1.0+1
     stacked: ^2.2.7
     stacked_services: ^0.8.15
    dev_dependencies:
     build_runner: ^2.1.5
     flutter_lints: ^1.0.0
     flutter_test:
      sdk: flutter
     stacked_generator: ^0.5.6
    flutter:
     uses-material-design: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would be using the &lt;a href="https://pub.dev/packages/faunadb_data" rel="noopener noreferrer"&gt;faunadb_data&lt;/a&gt; package to link the client's setup and perform queries on our database. &lt;/p&gt;

&lt;p&gt;Next, create a new file named todo.dart. Inside the class, create a class and name the class TodoModel. It has five parameters that make up each Todo. That's the id, todoName, todoContent, completed(status), date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class TodoModel extends Entity&amp;lt;TodoModel&amp;gt; {
     final String id;
     final String todoName;
     final String todoContent;
     final bool completed;
     final String date;
     TodoModel(
      this.id,
      this.todoName,
      this.todoContent,
      this.completed,
      this.date,
     );
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class extends the Entity class, which comes from faunadb_data. The fromJson, getId, and model methods act as overrides on the Entity class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class TodoModel extends Entity&amp;lt;TodoModel&amp;gt; {
    //The fromJson() method returns a TodoModel object with the key parameters in the map passed in. 
     @override
     TodoModel fromJson(Map&amp;lt;String, dynamic&amp;gt; model) {
      // TODO: implement fromJson
      throw UnimplementedError();
     }
     // The getId() method returns the id making it easier to fetch the id of a particular Todo Object. 
     @override
     String getId() {
      // TODO: implement getId
      throw UnimplementedError();
     }
     // The model() method returns a map with key-value pairs of the parameters for the TodoModel.
     @override
     Map&amp;lt;String, dynamic&amp;gt; model() {
      // TODO: implement model
      throw UnimplementedError();
     }
    }



    class TodoModel extends Entity&amp;lt;TodoModel&amp;gt; {
     final String id;
     final String todoName;
     final String todoContent;
     final bool completed;
     final String date;
     TodoModel(
      this.id,
      this.todoName,
      this.todoContent,
      this.completed,
      this.date,
     );
     @override
     TodoModel fromJson(Map&amp;lt;String, dynamic&amp;gt; model) {
      return TodoModel(
       model['id'] as String,
       model['todoName'] as String,
       model['todoContent'] as String,
       model['status'] as bool,
       model['date'] as String,
      );
     }
     @override
     String getId() {
      return id;
     }
     @override
     Map&amp;lt;String, dynamic&amp;gt; model() {
      Map&amp;lt;String, dynamic&amp;gt; model = {
       'id': id,
       'todoName': todoName,
       'todoContent': todoContent,
       'status': completed,
       'date': date,
      };
      return model;
     }

    // In addition to this, we create two static variables which point to the collection name and the index we created earlier. 
     static String collection() =&amp;gt; "todos";
     static String allTodosIndex() =&amp;gt; "all_todos";
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we have our TodoModel and its overriding methods all set up. &lt;/p&gt;

&lt;p&gt;We still need to set up the deserializer, which takes in a map and uses it to construct a TodoModel Object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    TodoModel getTodoFromJson(Map&amp;lt;String, dynamic&amp;gt; json) {
      return TodoModel(
        json['id'] as String,
        json['todoName'] as String,
        json['todoContent'] as String,
        json['status'] as bool,
        json['date'] as String,
      );
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next thing to set up is the repository class. This call which would be named TodoRepository would extends the FaunaRepository class which comes from the fauna_data class we are using. This class would link us to the database  we created in FaunaDB and also the specific index we want to use. We would pass both in the super constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class TodoRepository extends FaunaRepository&amp;lt;TodoModel&amp;gt; {
     TodoRepository() : super("todos", "all_todos");
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the super constructor, we pass the name of the collection and the index, the two things needed for the Repository setup.&lt;/p&gt;

&lt;p&gt;Moving forward, create a new folder named services; inside this folder, create a file named todo_service.dart with a class named TodoService. This class will be the intermediary between our app and the package we’re using. All the calls we’re making to the database would flow through this class. Methods to read, save, update, delete data from the database would go in here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:faunadb_data/faunadb_data.dart';
    import 'package:optional/optional.dart';
    import 'package:pilots/todo.dart';
    class TodoService {
     TodoRepository todoRepository = TodoRepository();

     //CRUD Operations in Fauna
     /// Create Operation
     saveTodo(TodoModel todo) async {
      await todoRepository.save(todo, getTodoFromJson);
     }
     /// Read Operation 1
     Future&amp;lt;List&amp;gt; getAllTodos() async {
    //The number of results per page would go into the size parameter, we are starting with 20 results per page here
      PaginationOptions po = PaginationOptions(size: Optional.of(20));
      final result = await todoRepository.findAll(po, getTodoFromJson);
      return result.data;
     }
     /// Read Operation 2
     Future&amp;lt;TodoModel&amp;gt; getSingleTodo(String id) async {
      final result = await todoRepository.find(id, getTodoFromJson);
      return result.value;
     }
     /// Update Operation
     updateTodo(TodoModel todo) async {
      await todoRepository.save(todo, getTodoFromJson);
     }
     /// Delete Operation
     deleteTodo(String id) async {
      final result = await todoRepository.remove(id, getTodoFromJson);
      return result.value;
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we are done setting up our services and other things needed to interact with our database smooth, let's create a new folder called UI. We’ll have two screens in the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;homeView, which displays the list of todos, and &lt;/li&gt;
&lt;li&gt;add_todos, which is where we’ll add the details for creating a new todo object. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the UI folder, create two folders named homeView and add_todos respectively. &lt;/p&gt;

&lt;p&gt;In the homeView folder, create two new files titled &lt;code&gt;home_view.dart&lt;/code&gt; and &lt;code&gt;home_viewmodel.dart&lt;/code&gt;. The business logic and functionalities would be in the viewmodel while the UI code would be in the view file.  &lt;/p&gt;

&lt;p&gt;Also, in the add_todos folder, create two new files also titled &lt;code&gt;add_todos_view.dart&lt;/code&gt; and &lt;code&gt;add_todos_viewmodel.dart&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;add_todo_viewmodel.dart&lt;/code&gt; and &lt;code&gt;home_viewmodel.dart&lt;/code&gt; files, create a class to extend the BaseViewModel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class AddTodoModel extends BaseViewModel {}


    class HomeViewModel extends BaseViewModel{}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the add_todos_view.dart file, create a Stateless widget and return the ViewModelBuilder.reactive() function from the Stacked package. Remembering I mentioned the viewmodel files would hold the logic for the view files. The ViewModelBuilder.reactive() constructor would serve as a binding between a view file and it’s corresponding viewmodel. That way, a view can access and make use of logic declared in the viewmodel in its view file.&lt;/p&gt;

&lt;p&gt;Here is the homeView now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class HomeView extends StatelessWidget {
     const HomeView({Key? key}) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;HomeViewModel&amp;gt;.reactive(
       viewModelBuilder: () =&amp;gt; HomeViewModel(),
       onModelReady: (viewModel) =&amp;gt; viewModel.setUp(),
       builder: (context, viewModel, child) {
        return Scaffold();
       },
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the addTodoView too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class AddTodoView extends StatelessWidget {
     AddTodoView({
      Key? key,
     }) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;AddTodoModel&amp;gt;.reactive(
       viewModelBuilder: () =&amp;gt; AddTodoModel(),
       builder: (context, viewModel, child) {
        return Scaffold();
       },
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing is to set up our routes and register the services, making it easier to use them across the entire codebase using the locator. Create a new folder named app. In this folder, create a new file and call it app.dart. To register the services, we’ll make use of the &lt;code&gt;@StackedApp&lt;/code&gt; annotation. This gives us access to two parameters, routes and dependencies. In the dependencies block, we’ll register the TodoService and NavigationService. Also, we’ll declare the routes for the pages we’ll use, i.e. the HomeView and the AddTodoView.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @StackedApp(
     routes: [
      MaterialRoute(page: AddTodoView),
      MaterialRoute(page: HomeView),
     ],
     dependencies: [
      LazySingleton(classType: NavigationService),
      LazySingleton(classType: TodoService),
     ],
    )
    class AppSetup {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the flutter command below to generate the files needed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`flutter pub run build_runner build --delete-conflicting-outputs`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command generates the &lt;code&gt;app.locator.dart&lt;/code&gt; and &lt;code&gt;app.router.dart&lt;/code&gt; file into which our dependencies and routes are registered.&lt;/p&gt;

&lt;p&gt;Go to your &lt;code&gt;main.dart&lt;/code&gt; file; in the main block, above the runApp(), we need to set up the locator and the DB key that the app would use to access the DB. Recall the key we created earlier while setting up our DB on the Fauna account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    void main() {
     WidgetsFlutterBinding.ensureInitialized();
     setCurrentUserDbKey("//YOUR-KEY-GOES-HERE");
     setupLocator();
     runApp(MyApp());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are done with all the setups and configurations we need to do. We can start building the UIs and writing the business logic in the ViewModel.&lt;/p&gt;

&lt;p&gt;In HomeViewModel, we define methods to get all the todos currently in the database anytime we start the app (read operation on the DB). Another function is to delete a particular Todo. Using the locator, we inject the services and use them to access the methods we've set up in the TodoService class earlier. The list of todos is what the UI screen will use in building the screen. Also, since we want the current list of todos in our DB to show once we start the application, we create a function called runBusyFuture, which tells the ViewModel*, "Hey, I'm currently fetching essential data,* &lt;em&gt;s&lt;/em&gt;&lt;em&gt;o hold on and display a loading indicator&lt;/em&gt;". This function is safer to adjust our UI based on the state, the list of todos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class HomeViewModel extends BaseViewModel {
     final _todoService = locator&amp;lt;TodoService&amp;gt;();
     final _navigationService = locator&amp;lt;NavigationService&amp;gt;();
     List&amp;lt;dynamic&amp;gt; todosList = [];

     Future&amp;lt;void&amp;gt; setUp() async {
      await runBusyFuture(getTodos());
     }

     Future&amp;lt;void&amp;gt; getTodos() async {
      todosList = await _todoService.getAllTodos();
     }

     Future&amp;lt;void&amp;gt; deleteTodo(String id) async {
      await _todoService.deleteTodo(id);
      todosList = await _todoService.getAllTodos();
      notifyListeners();
     }

     navigateToAddTodoPage() {
      _navigationService.navigateTo(Routes.addTodoView);
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the addNewTodo ViewModel, we declare the method to save the details of the new Todo and create the Todo; after the Todo gets completed, we route the user to the HomeView, which displays the list of all the Todos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class AddTodoModel extends BaseViewModel {
     final service = locator&amp;lt;TodoService&amp;gt;();
     TodoRepository repo = TodoRepository();
     bool status = false;
     NavigationService navigationService = NavigationService();

     Future&amp;lt;void&amp;gt; createTodo(String name, String content) async {
      Optional&amp;lt;String&amp;gt; uniqueId = await repo.nextId();
      String id = uniqueId.value;
      TodoModel newTodo = TodoModel(id, name, content, status, formatDate());
      final result = await service.saveTodo(newTodo);
      navigateToHome();
     }

     String formatDate() {
      DateTime now = DateTime.now();
      String formattedDate = DateFormat('MMMM d' + ', ' + 'y').format(now);
      return formattedDate;
     }

     void navigateToHome() {
      navigationService.navigateTo(Routes.homeView);
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, to fill the UI screen, we would use a ListViewBuilder to display the elements of the list we get from the database. You can check the gist for the complete code &lt;a href="https://gist.github.com/Blazebrain/b68261d050c988b07d8e2dbe84449d8d" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the addNewTodo, we would be using a Form. At the top of the file, use the @FormView annotation; this gives access to the fields. In the field block, add the fields in the form using the FormTextField and attach the generated mixin to the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    class AddTodoView extends StatelessWidget with $AddTodoView {


    @FormView(fields: [
     FormTextField(name: 'todoName'),
     FormTextField(name: 'todoContent'),
    ])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the flutter command to generate the file. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`flutter pub run build_runner build --delete-conflicting-outputs`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It would contain the mixin for managing the controllers, which you would assign to the fields in the Form. &lt;/p&gt;

&lt;p&gt;For the todoName FormField:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    TextFormField(
     controller: todoNameController,
     focusNode: todoNameFocusNode,
     decoration: const InputDecoration(
      label: Text('Title'),
      border: OutlineInputBorder(
       borderSide: BorderSide(),
       borderRadius: BorderRadius.all(
        Radius.circular(16.0),
       ),
      ),
     ),
    ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for the todoContent FormField:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    TextFormField(
         controller: todoContentController,
         focusNode: todoContentFocusNode,
         decoration: const InputDecoration(
          label: Text('Content'),
          border: OutlineInputBorder(
           borderSide: BorderSide(),
           borderRadius: BorderRadius.all(
            Radius.circular(16.0),
           ),
          ),
         ),
        ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check out the complete code for the UI screen in this gist &lt;a href="https://gist.github.com/Blazebrain/87d96dc33fd4bb52a963f3ddc5c99889" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Save and run the application, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o39jwb02vavzuzm2g2y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o39jwb02vavzuzm2g2y.gif" width="256" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check out the complete code for the sample app &lt;a href="https://github.com/Blazebrain/faunadb_sample_project" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's a wrap! We've officially integrated the Fauna into our Flutter app and built a fully functional Todo List Application along the way. Fauna is fast, smooth and easy to use and takes just a few steps to set up and integrate. Check out the official documentation for further study. Keep learning, keep building and definitely, keep using Fauna.&lt;/p&gt;

&lt;p&gt;If you have any questions, don't hesitate to reach out to me on Twitter: &lt;a href="https://www.twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt; or LinkedIn: &lt;a href="https://www.linkedin.com/in/david-adegoke" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written in connection with the&lt;/em&gt; &lt;a href="https://fauna.com/blog/write-with-fauna" rel="noopener noreferrer"&gt;&lt;em&gt;Write with Fauna&lt;/em&gt;&lt;/a&gt; &lt;em&gt;Program.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>fauna</category>
      <category>stacked</category>
      <category>dart</category>
    </item>
    <item>
      <title>Using Services in Flutter</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Mon, 01 Nov 2021 14:14:19 +0000</pubDate>
      <link>https://dev.to/blazebrain/using-services-in-flutter-572h</link>
      <guid>https://dev.to/blazebrain/using-services-in-flutter-572h</guid>
      <description>&lt;p&gt;One primary criterion for building a fully scalable and maintainable application is the reusability of code. Complex numbers of code repetitions would result in many potential bugs. When there needs to be a change in the package offering a particular service to the app, a painfully long process would be required to completely swap out implementations in the app. That itself is a nightmare for developers and can be the launching pad to failure for a product/company.&lt;/p&gt;

&lt;p&gt;This article will introduce you to Services in Flutter, along with their key benefits, and show example code. This article assumes you have a Flutter development environment setup and have been building apps with Flutter. If not, you can check out this guide from Flutter on getting started building Flutter apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Services are classes that offer a specific functionality. A Service is a class that uses methods that enable it to provide a specialized feature, emphasizing specialized. A Service class offers just one distinct input to the app. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ApiService&lt;/li&gt;
&lt;li&gt;LocalStorageService&lt;/li&gt;
&lt;li&gt;ConnectivityService&lt;/li&gt;
&lt;li&gt;ThemeService&lt;/li&gt;
&lt;li&gt;MediaService etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice how each of the services listed out there offers one distinct feature. They keep the codebase as clean as possible and reduce the number of repeated codes on the codebase.&lt;/p&gt;

&lt;p&gt;Services abstract functionalities got from a third-party source and reduced the dependence of the entire app on the goodwill of the package maintainer. For an app that depends directly on the packages, if the package maintainers abandon the package and there are no updates, it would break the app. When a decision is made later on to swap the package for another, there would be a lot involved in the process as developers would have to search through the codebase for places the package is used and then manually swap them. This process is painfully long and would cost development time and resources that the app could have better used.&lt;/p&gt;

&lt;p&gt;The app does not depend on the 3rd party package but depends on the Service class. Hence, when there is a need for a swap, the only thing that would need to be changed would be functions from the packages the Service depends on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Let's use the MediaService to fetch an image from the user's phone and displays it on the screen. The first thing is to create a new project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    flutter create intro_to_service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, import &lt;a href="https://pub.dev/packages/stacked/install" rel="noopener noreferrer"&gt;stacked&lt;/a&gt; and &lt;a href="https://pub.dev/packages/image_picker" rel="noopener noreferrer"&gt;image_picker&lt;/a&gt; packages, which Flutter would use in the project in the dependencies section of the &lt;code&gt;pubspec&lt;/code&gt; YAML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    dependencies: 
     image_picker: ^0.8.4+3
     stacked: ^2.2.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the dev dependencies section, import the &lt;a href="https://pub.dev/packages/build_runner" rel="noopener noreferrer"&gt;build_runner&lt;/a&gt; and &lt;a href="https://pub.dev/packages?q=stacked+generator" rel="noopener noreferrer"&gt;stacked generator&lt;/a&gt;, which would be responsible for generating files from the annotations used in the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    dev_dependencies:
     build_runner: ^2.1.4
     stacked_generator: ^0.5.5 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, head over to your &lt;code&gt;main.dart&lt;/code&gt; file. Clear out the default counter app code, create a new material app, and pass an &lt;code&gt;HomeView&lt;/code&gt; to the home parameter (The &lt;code&gt;HomeView&lt;/code&gt; will be created later).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:flutter/material.dart';
    import 'package:intro_to_services/app/app.locator.dart';
    import 'views/home_view/home_view.dart';
    void main() {
     runApp(MyApp());
    }
    class MyApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
      return const MaterialApp(
       title: 'Material App',
       home: HomeView(),
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would be making use of the &lt;a href="https://pub.dev/packages/image_picker" rel="noopener noreferrer"&gt;image_picker&lt;/a&gt; package and picking the image from the gallery. &lt;/p&gt;

&lt;p&gt;Create a folder named services; inside this folder, create a new file titled &lt;code&gt;media_service.dart&lt;/code&gt;. This is where the code for setting up the Service would be stored.&lt;/p&gt;

&lt;p&gt;Next, create the method to get the image; we provide it with a parameter &lt;code&gt;fromGallery&lt;/code&gt; to indicate if we would be using the Camera or taking the image from the gallery. The &lt;code&gt;image_picker&lt;/code&gt; package gives us access to both.&lt;/p&gt;

&lt;p&gt;This method would call the &lt;code&gt;pickImage&lt;/code&gt; function the package gives us access to and use the &lt;code&gt;fromGallery&lt;/code&gt; parameter to determine if we would get the image from the gallery or use the Camera.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'dart:io';
    import 'package:image_picker/image_picker.dart';
    class MediaService {
     final ImagePicker _picker = ImagePicker();
     Future&amp;lt;File?&amp;gt; getImage({required bool fromGallery}) async {

      final XFile? image = await _picker.pickImage(
       source: fromGallery ? ImageSource.gallery : ImageSource.camera,
      );
      final File? file = File(image!.path);
      return file;
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getImage&lt;/code&gt; method then returns the file that was selected to be used inside the application. That wraps up the MediaService we would be using. &lt;/p&gt;

&lt;p&gt;Next, set up the locator file and register this Service that any class can use within the codebase. Create a new folder and name it &lt;code&gt;app&lt;/code&gt;. In this folder, create a file named &lt;code&gt;app.dart&lt;/code&gt;. This file would hold the setup for registering our services and other dependencies across the app. &lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;app.dart&lt;/code&gt; file, create a class named &lt;code&gt;AppSetup&lt;/code&gt; and annotate it with the &lt;code&gt;@StackedApp&lt;/code&gt; annotation. This annotation takes in a few parameters, among which are the routes and dependencies. The various services to be used within the app would be registered within the dependencies block of the &lt;code&gt;StackedApp&lt;/code&gt; annotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:intro_to_services/services/media_service.dart';
    import 'package:stacked/stacked_annotations.dart';
    @StackedApp(
     dependencies: [
      LazySingleton(classType: MediaService),
     ],
    )
    class AppSetup {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the block, we register the Service as a &lt;code&gt;LazySingleton&lt;/code&gt;, meaning it won't be initialized until it is used in the application. The classtype is the name of the class, which is MediaService. &lt;/p&gt;

&lt;p&gt;Next, run the command to generate the locator file from the &lt;code&gt;StackedApp&lt;/code&gt; annotation using the &lt;a href="https://pub.dev/packages?q=stacked+generator" rel="noopener noreferrer"&gt;stacked generator&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    flutter pub run build_runner build --delete-conflicting-outputs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a function in this generated file, the &lt;code&gt;setupLocator()&lt;/code&gt; function, which sets up the environment and registers the Service. We call this function in the main block in the &lt;code&gt;main.dart&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    void main() {
     WidgetsFlutterBinding.ensureInitialized();
     setupLocator();
     runApp(MyApp());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we have successfully created the Service and registered it in the locator file, making the Service available for use in any part of the codebase. &lt;/p&gt;

&lt;p&gt;Next, set up the &lt;code&gt;homeView&lt;/code&gt; and its &lt;code&gt;ViewModel&lt;/code&gt;. Create a new folder in the lib directory titled views. Inside this folder, create the folder which would hold the homeView and homeViewModel files. Name this folder home_view. Create the two files and name them &lt;code&gt;home_view.dart&lt;/code&gt; and &lt;code&gt;home_viewmodel.dart&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;homeViewModel&lt;/code&gt; file, create a class named &lt;code&gt;HomeViewModel&lt;/code&gt; which extends the &lt;code&gt;BaseViewModel&lt;/code&gt; from the &lt;a href="https://pub.dev/packages/stacked/install" rel="noopener noreferrer"&gt;stacked&lt;/a&gt; package. In this class, we first declare a variable that would access the &lt;code&gt;MediaService&lt;/code&gt; through the locator. The locator gives us access to the entire Service and its methods. Next, we declare a private nullable image of File type. We then link it to a getter for access by outside classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'dart:io';
    import 'package:intro_to_services/app/app.locator.dart';
    import 'package:intro_to_services/services/media_service.dart';
    import 'package:stacked/stacked.dart';
    class HomeViewModel extends BaseViewModel {
     final mediaService = locator&amp;lt;MediaService&amp;gt;();
     File? _image;
     File? get imageFromGallery =&amp;gt; _image;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, set up the method to make the call to the Service and fetch the image. The call to the &lt;code&gt;getImage&lt;/code&gt; function of the Service returns a file that we pass to the _image variable we created earlier. We then call &lt;code&gt;notifyListeners&lt;/code&gt; provided by the &lt;code&gt;BaseViewModel&lt;/code&gt; class from the &lt;a href="https://pub.dev/packages/stacked/install" rel="noopener noreferrer"&gt;stacked&lt;/a&gt; package. The &lt;code&gt;notifyListerners()&lt;/code&gt; call would inform the views bound to this &lt;code&gt;ViewModel&lt;/code&gt; that there has been a state change and that the views should perform a rebuild.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Future&amp;lt;void&amp;gt; getImageFromGallery() async {
      _image = await mediaService.getImage(fromGallery: true);
      notifyListeners();
     }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, setting up the view itself. Create a stateless widget named &lt;code&gt;HomeView&lt;/code&gt; in the home_view.dart file. This widget returns the &lt;code&gt;viewModelBuilder&lt;/code&gt; widget from stacked, which binds the view to the &lt;code&gt;ViewModel&lt;/code&gt;. We pass in the &lt;code&gt;ViewModel&lt;/code&gt; to the &lt;code&gt;viewModelBuilder&lt;/code&gt; function parameter and a Scaffold to the builder parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:flutter/material.dart';
    import 'package:stacked/stacked.dart';
    import 'home_viewmodel.dart';
    class HomeView extends StatelessWidget {
     const HomeView({Key? key}) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;HomeViewModel&amp;gt;.reactive(
       viewModelBuilder: () =&amp;gt; HomeViewModel(),
       builder: (context, viewModel, child) {
        return Scaffold();
       },
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the UI itself, we create a TextButton and pass the function to get the image from the &lt;code&gt;ViewModel&lt;/code&gt; in its onPressed Function; this would get the image from the gallery and makes it available for use in the view through the getter we declared in the &lt;code&gt;ViewModel&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     TextButton(
       onPressed: () {
        viewModel.getImageFromGallery();
       },
       child: const Text('Fetch Image'),
     )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, if the image is not null, we want to display the image in the view if the user has selected an image. Using the &lt;code&gt;image.file&lt;/code&gt; from Flutter, we display the selected image from the gallery to the user in the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     if (viewModel.imageFromGallery != null)
       Image.file(
        viewModel.imageFromGallery!,
         height: 30,
         width: 30,
       ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the complete code for the home_view.dart view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:flutter/material.dart';
    import 'package:stacked/stacked.dart';
    import 'home_viewmodel.dart';
    class HomeView extends StatelessWidget {
     const HomeView({Key? key}) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;HomeViewModel&amp;gt;.reactive(
        viewModelBuilder: () =&amp;gt; HomeViewModel(),
        builder: (context, viewModel, child) {
         return Scaffold(
          body: Center(
           child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
             if (viewModel.imageFromGallery != null)
              Image.file(
               viewModel.imageFromGallery!,
               height: 100,
               width: 100,
              ),
             TextButton(
              onPressed: () {
               viewModel.getImageFromGallery();
              },
              child: const Text('Fetch Image'),
             )
            ],
           ),
          ),
         );
        });
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the complete code for the sample app &lt;a href="https://github.com/Blazebrain/intro_to_services" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Don't forget to drop a star on the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hurray, you have successfully learned how to create a service, declare it and use it anywhere within your application.&lt;/p&gt;

&lt;p&gt;Services reduce the number of codes that would be reused within the application making the codebase cleaner and better organized. Services also protect us from the pain of manually swapping out implementations when there is a change in the third-party package being used within the codebase.&lt;/p&gt;

&lt;p&gt;Services offer benefits that speed up the development time and effectively use available resources. Not using them yet? Try them out, and you will see the impact it would make on your codebase.&lt;/p&gt;

&lt;p&gt;If you have any questions, don't hesitate to reach out to me on Twitter: &lt;a href="https://www.twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt; or LinkedIn: &lt;a href="https://www.linkedin.com/in/david-adegoke" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>architecture</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Using Stacked Architecture in Flutter App</title>
      <dc:creator>Blazebrain</dc:creator>
      <pubDate>Mon, 01 Nov 2021 14:13:37 +0000</pubDate>
      <link>https://dev.to/blazebrain/using-stacked-architecture-in-flutter-app-2ecg</link>
      <guid>https://dev.to/blazebrain/using-stacked-architecture-in-flutter-app-2ecg</guid>
      <description>&lt;p&gt;The concept of Architecture is one of the most diverse topics in the world of programming today. A lot of solutions have been developed, all aimed at fixing one flaw or the other. App Architecture is one of the topics where personal choice has been advised to come in. If one meets your needs efficiently and enables you to release good, quality code, then go for it.&lt;/p&gt;

&lt;p&gt;This article aims to introduce you to Stacked Architecture, an architecture that offers clean, efficient solutions to architecture your next Flutter app. From dependency Injection to the right out of the box services to layered structures that follow the principles of &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;Clean Architecture&lt;/a&gt; and a whole lot. To get started on development with Flutter, check out this &lt;a href="https://flutter.dev/docs/get-started/install" rel="noopener noreferrer"&gt;article&lt;/a&gt; from the Flutter team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/stacked" rel="noopener noreferrer"&gt;Stacked Architecture,&lt;/a&gt; developed by Dane Mackier from &lt;a href="https://www.filledstacks.com/" rel="noopener noreferrer"&gt;FilledStacks&lt;/a&gt;, is an MVVM Architecture solution that offers a lot of components for building a highly scalable, testable, maintainable, and usable Flutter application. From&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State Management,&lt;/li&gt;
&lt;li&gt;Dependency Injection (Dependency Inversion),&lt;/li&gt;
&lt;li&gt;Navigation Abstraction,&lt;/li&gt;
&lt;li&gt;Services (Out-of-the-box),&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a whole lot more. All of these are offered by the Stacked Architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;Handling State in Flutter application using Stacked couldn’t be much better. It provides widgets and constructors which control how the state is being passed and managed in the application. Let’s dive into it using a sample app.&lt;/p&gt;

&lt;p&gt;The first thing is to create a new Flutter project,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     flutter create intro_to_stacked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates all the files and folders, which lays the foundation of the flutter app. &lt;br&gt;
Next is to add &lt;a href="https://pub.dev/packages/stacked" rel="noopener noreferrer"&gt;stacked&lt;/a&gt; as a dependency in the pubspec.yaml file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    stacked: ^2.2.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to set up the basic folder structure for the sample app. Go to the lib folder and create a new folder titled home. Inside this, create two files named home_view.dart and home_viewmodel.dart. The homeViewModel file would be responsible for managing the state of the homeView, which is shown to the user. Clean Architecture, which says the view should contain zero logic, is strictly adhered to; the logic resides in the ViewModel.&lt;/p&gt;

&lt;p&gt;The view is bound to the ViewModel using the ViewModelBuilder widget, which Stacked offers. This widget takes in 2 parameters which are &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;builder, which builds the UI that has its state in the ViewModel&lt;/li&gt;
&lt;li&gt;viewModelBuilder, which is the function that would return the ViewModel for this widget.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:flutter/material.dart';
    import 'package:stacked/stacked.dart';
    import 'package:intro_to_stacked/ui/views/home/home_viewmodel.dart';

    class HomeView extends StatelessWidget {
     const HomeView({Key? key}) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;HomeViewModel&amp;gt;.reactive(
       viewModelBuilder:()=&amp;gt; HomeViewModel(),
       builder: (context, model, child) {
        return Scaffold();
       },
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ViewModelBuilder offers two constructors that deal with how the state is managed and subsequently update the UI for the application. They are the .reactive() and the .nonReactive() constructors. The .reactive() rebuilds the UI every time notifyListeners is called in the ViewModel. However, the .nonReactive() constructor rebuilds the UI once, after which it doesn’t rebuild on subsequent calls in the ViewModel. &lt;/p&gt;

&lt;p&gt;With that, we’ve set up the view file, moving to the ViewModel, we create a class that extends the BaseViewModel class that stacked provides. The BaseViewModel class provides functionalities used for maintaining the state in the application. In the ViewModel, we have a String that says Stacked is cool (definitely true). This String is the state currently offered by the ViewModel and which would need to be displayed on the screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:stacked/stacked.dart';

    class HomeViewModel extends BaseViewModel {
     final String _declaration = 'Stacked is soo cool';
     String get myDeclaration =&amp;gt; _declaration;

    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to the view, to use this state in our builder, we use the model offered by the builder connecting the state in the ViewModel to the UI screen which uses it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Scaffold(
         body: Center(
          child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
           children: [
            const Text('Stacked Introduction'),
            Text(model.myDeclaration),
           ],
          ),
         ),
        );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On updating the state in the application, let’s have a function that updates the text and calls notifyListeners after. We would link this function to the onPressed of a TextButton.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    //In View(home_view.dart)
     TextButton(
      onPressed: () =&amp;gt; model.updateDeclaration(),
      child: const Text('Update Text'),
     )

    //In ViewModel (home_viewmodel.dart)
     void updateDeclaration() {
      _declaration = 'I say Stacked is sooo cool';
      notifyListeners();
     }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The notifyListeners call informs the view to rebuild as there has been a state change in the ViewModel.&lt;/p&gt;

&lt;p&gt;For a deep dive into the state management solution offered, check out this &lt;a href="https://www.filledstacks.com/post/flutter-state-management-with-stacked/" rel="noopener noreferrer"&gt;article&lt;/a&gt; provided by the FilledStacks team. &lt;/p&gt;

&lt;h2&gt;
  
  
  How about Navigation and Dependency Injection?
&lt;/h2&gt;

&lt;p&gt;Stacked provides a direct out the box to navigation without context. Using the NavigationService it gives, we can smoothly declare our navigation in our ViewModel and use them in the view. This NavigationService allows for a clean UI without the interference of logic or complex routing codes. With the aid of the build runner and stacked generator, we can auto-generate routes and smoothly perform navigation.&lt;/p&gt;

&lt;p&gt;Let’s get to it.&lt;/p&gt;

&lt;p&gt;The first is to add &lt;a href="https://pub.dev/packages/build_runner" rel="noopener noreferrer"&gt;build_runner&lt;/a&gt; and &lt;a href="https://pub.dev/packages/stacked_generator" rel="noopener noreferrer"&gt;stacked_generator&lt;/a&gt; to the dev_dependencies section in your pubspec.yaml file. Also, add the &lt;a href="https://pub.dev/packages/stacked_services" rel="noopener noreferrer"&gt;stacked_services&lt;/a&gt; to the dependency section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    dependencies:
     stacked: ^2.2.7
     stacked_services: ^0.8.15

    dev_dependencies:
     build_runner: ^2.1.4
     stacked_generator: ^0.5.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the &lt;code&gt;flutter pub get&lt;/code&gt; command to get the files locally for use.&lt;/p&gt;

&lt;p&gt;Next is to create the new view that we would be routing to. Create a folder inside views and name it profile. Inside this folder, create two files, the profile_view.dart and profile_viewmodel.dart. &lt;/p&gt;

&lt;p&gt;In profile_viewmodel.dart, create a class named ProfileViewModel which extends BaseViewModel. In the ViewModel, we declare a String that the app would display on the view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:stacked/stacked.dart';

    class ProfileViewModel extends BaseViewModel {
     String _pageName = 'This is the Profile Page';
     String get pageName =&amp;gt; _pageName;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In profile_view.dart, create the stateless widget which returns the ViewModelBuilder and bind it to the ProfileViewModel. This view would contain a similar setup to the HomeView; it would display a Profile View text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:flutter/material.dart';
    import 'package:intro_to_stacked/ui/views/profile/profile_viewmodel.dart';
    import 'package:stacked/stacked.dart';
    class ProfileView extends StatelessWidget {
     const ProfileView({Key? key}) : super(key: key);
     @override
     Widget build(BuildContext context) {
      return ViewModelBuilder&amp;lt;ProfileViewModel&amp;gt;.reactive(
       viewModelBuilder: () =&amp;gt; ProfileViewModel(),
       builder: (context, viewModel, child) {
        return Scaffold(
         body: Center(
          child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: [
            Text(viewModel.pageName),
           ],
          ),
         ),
        );
       },
      );
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing is to create a folder in lib named app. Inside this folder, create a new file titled app.dart. In this file would all the code needed for routing along with the dependencies.&lt;/p&gt;

&lt;p&gt;Create a class named AppSetup and annotate it with the StackedApp; this class houses the annotation; it does nothing else asides that. The main focus is the annotation as it takes in two parameters, routes, and dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @StackedApp()
    class AppSetup {
     /** This class has no puporse besides housing the annotation that generates the required functionality **/
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stacked offers three different types of routes which determines the mode of transition&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MaterialRoute&lt;/li&gt;
&lt;li&gt;CupertinoRoute&lt;/li&gt;
&lt;li&gt;CustomRoute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the MaterialRoute, we register the Views present in the app that would use the NavigationService.&lt;/p&gt;

&lt;p&gt;In addition to the routes, we would declare the dependencies we would be using in the app, enabling Stacked to create the locator file that would handle the injection of the declared types. We would register the NavigationService as a LazySingleton, which means it won’t be initialized until used for the first time in the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import '../ui/views/home/home_view.dart';
    import '../ui/views/profile/profile_view.dart';
    import 'package:stacked/stacked_annotations.dart';
    @StackedApp(
     routes: [
      MaterialRoute(page: HomeView, initial: true),
      MaterialRoute(page: ProfileView)
     ],
     dependencies: [
      LazySingleton(classType: NavigationService),
     ],
    )
    class AppSetUp {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the HomeView is the first page we contact, we set the initial parameter to true. &lt;/p&gt;

&lt;p&gt;After setting this up, run the flutter command to auto-generate the needed files for routing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    flutter pub run build_runner build --delete-conflicting-outputs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command would generate the files needed for navigation and dependency injection setup. &lt;/p&gt;

&lt;p&gt;The last step in this process is to convert the main top-level function of the app into a Future and await the setupLocator function in the app.locator.dart file generated by the command used earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Future main() async {
     WidgetsFlutterBinding.ensureInitialized();
     await setupLocator();
     runApp(MyApp());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do we use it?
&lt;/h2&gt;

&lt;p&gt;To make use of the navigation in the HomeView, we create a function in the HomeViewModel that would perform the navigation. First, we declare the locator which would give us access to the Navigation Service we registered earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import 'package:intro_to_stacked/app/app.router.dart';
    import '../../../app/app.locator.dart';
    import 'package:stacked/stacked.dart';
    import 'package:stacked_services/stacked_services.dart';

    class HomeViewModel extends BaseViewModel {
     String _declaration = 'Stacked is soo cool';
     String get myDeclaration =&amp;gt; _declaration;
     final _navigationService = locator&amp;lt;NavigationService&amp;gt;();

     void navigateToProfileView() {
      _navigationService.navigateTo(Routes.profileView);
     }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing is to create a button in the view and pass the function to its onPressed parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     TextButton(
       onPressed: () =&amp;gt; model.navigateToProfileView(),
       child: const Text('Go To Profile View'),
     )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the files and run the app; you would see the button there, click the button and see the seamless transition that we achieve using the NavigationService Stacked provides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Services
&lt;/h2&gt;

&lt;p&gt;Stacked offers several services which can be set up and used within the app. These services include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NavigationService&lt;/li&gt;
&lt;li&gt;BottomSheetService&lt;/li&gt;
&lt;li&gt;DialogService&lt;/li&gt;
&lt;li&gt;SnackbarService&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These services can be set up and customized to fit various use cases, and similar to the NavigationService, they can be registered and used within the app on the fly. For further information, check out the &lt;a href="https://pub.dev/packages/stacked_services" rel="noopener noreferrer"&gt;package&lt;/a&gt; on pub.dev and also the articles on &lt;a href="https://www.filledstacks.com/" rel="noopener noreferrer"&gt;FilledStacks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Stacked Architecture is a super pack ready to be discharged and used to build clean, scalable applications on the fly. This article has explained some of the concepts and components of Stacked Architecture, and with it, we have created a sample app that uses these components. Check out &lt;a href="https://www.filledstacks.com/" rel="noopener noreferrer"&gt;FilledStack&lt;/a&gt; for further information on the various features that make up the Stacked Architecture.&lt;/p&gt;

&lt;p&gt;You can find the code for the sample app &lt;a href="https://github.com/Blazebrain/intro_to_stacked" rel="noopener noreferrer"&gt;here&lt;/a&gt;. If you have any questions, don't hesitate to reach out to me on Twitter: &lt;a href="https://www.twitter.com/Blazebrain01" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt; or LinkedIn: &lt;a href="https://www.linkedin.com/in/david-adegoke" rel="noopener noreferrer"&gt;@Blazebrain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
