<?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: ASAMOAH MICHAEL</title>
    <description>The latest articles on DEV Community by ASAMOAH MICHAEL (@iamsirmike).</description>
    <link>https://dev.to/iamsirmike</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%2F75288%2F752310b8-51a8-48cd-8bd6-c727bd70d63c.jpg</url>
      <title>DEV Community: ASAMOAH MICHAEL</title>
      <link>https://dev.to/iamsirmike</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamsirmike"/>
    <language>en</language>
    <item>
      <title>Streamlining Asynchronous Operations in Flutter with Error Handling and Retry Mechanism</title>
      <dc:creator>ASAMOAH MICHAEL</dc:creator>
      <pubDate>Mon, 10 Mar 2025 20:16:14 +0000</pubDate>
      <link>https://dev.to/iamsirmike/streamlining-asynchronous-operations-in-flutter-with-error-handling-and-retry-mechanism-3od7</link>
      <guid>https://dev.to/iamsirmike/streamlining-asynchronous-operations-in-flutter-with-error-handling-and-retry-mechanism-3od7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Handling asynchronous operations in Flutter can be challenging, especially when dealing with API calls, error handling, retries, loading states, and user-friendly feedback mechanisms.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore a reusable framework that simplifies async operations by handling these challenges while keeping your codebase clean and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When working with API calls and other asynchronous tasks, Flutter developers frequently face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repetitive try-catch blocks scattered throughout the codebase&lt;/li&gt;
&lt;li&gt;Inconsistent error handling approaches&lt;/li&gt;
&lt;li&gt;Manual management of loading indicators&lt;/li&gt;
&lt;li&gt;Allowing users to retry failed operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A centralized approach can help standardize how we execute async operations, making the codebase cleaner and more maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: OperationRunnerState
&lt;/h2&gt;

&lt;p&gt;The OperationRunnerState class provides a reusable way to execute operations while handling errors and loading states.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulates operation execution: Abstracts away repetitive error handling and loading UI logic.&lt;/li&gt;
&lt;li&gt;Error Handling: Catches API (DioException) and generic errors, displaying appropriate messages.&lt;/li&gt;
&lt;li&gt;Intuitive Retry Mechanism: Allow users to retry failed operations with a single tap&lt;/li&gt;
&lt;li&gt;Clean Implementation: Reduce boilerplate with a simple, reusable pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Details
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Operation Type&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;typedef Operation&amp;lt;T&amp;gt; = Future&amp;lt;T&amp;gt; Function();&lt;/code&gt;&lt;br&gt;
This simple typedef defines &lt;code&gt;Operation&amp;lt;T&amp;gt;&lt;/code&gt; as a function that returns a &lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt;, allowing flexibility to execute any async task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Executing an Operation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abstract class OperationRunnerState&amp;lt;T extends StatefulWidget&amp;gt; extends State&amp;lt;T&amp;gt; {
  @protected
  Future&amp;lt;T?&amp;gt; runOperation&amp;lt;T&amp;gt;(
    Operation operation, {
    BuildContext? contextE,
    bool showLoader = true,
  }) async {
    contextE ??= context;

    Future&amp;lt;void&amp;gt; retryOperation() async {
      await runOperation(
        operation,
        contextE: contextE,
        showLoader: showLoader,
      );
    }

    try {
      if (showLoader) showLoading(context, loadingText: loadingText);

      final result = await operation();

      if (showLoader) Navigator.pop(context);

      return result as T;
    } on DioException catch (e) {
      _handleException(context, e.message, showLoader, retryOperation);
    } catch (e) {
      await _handleErrors(
        context,
        e.toString(),
        retryOperation,
      );
      return null;
    }
    return null;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void _handleException(
  BuildContext context, 
  String? message, 
  bool showLoader,
  Future&amp;lt;void&amp;gt; Function()? retryCallback
) async {
  if (showLoader) Navigator.pop(context);
  _handleErrors(context, message ?? "An error occurred", retryCallback);
}

Future&amp;lt;Object?&amp;gt; _handleErrors(
  BuildContext context, 
  String message,
  Future&amp;lt;void&amp;gt; Function()? retryCallback
) async {
  final shouldRetry = await context.pushNamed(errorScreenRoute, extra: {
    "errorMessage": message,
    "onRetry": retryCallback,
  });

  if (shouldRetry &amp;amp;&amp;amp; retryCallback != null) {
    await retryCallback(); 
  }

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Showing a Loading Indicator&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void showLoading(BuildContext context, {String? loadingText}) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (context) {
      return LoadingIndicator(loadingText: loadingText);
    },
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage Example&lt;/strong&gt;&lt;br&gt;
Here's how you can use OperationRunnerState in your widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ProductListScreen extends StatefulWidget {
  @override
  _ProductListScreenState createState() =&amp;gt; _ProductListScreenState();
}

class _ProductListScreenState extends OperationRunnerState&amp;lt;ProductListScreen&amp;gt; {
  List&amp;lt;Product&amp;gt; products = [];

  @override
  void initState() {
    super.initState();
    _fetchProducts();
  }

  Future&amp;lt;void&amp;gt; _fetchProducts() async {
    final result = await runOperation&amp;lt;List&amp;lt;Product&amp;gt;&amp;gt;(
      () =&amp;gt; apiService.getProducts(),
    );

    if (result != null) {
      setState(() =&amp;gt; products = result);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Products')),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) =&amp;gt; ProductTile(products[index]),
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;DRY Principle: Write error handling logic once, use it everywhere&lt;/li&gt;
&lt;li&gt;Consistent UX: Provide uniform feedback across your entire application and allows retrying failed operations&lt;/li&gt;
&lt;li&gt;Enhanced Maintainability: Centralize complex async operation management&lt;/li&gt;
&lt;li&gt;Developer Productivity: Focus on business logic instead of error handling&lt;/li&gt;
&lt;li&gt;Improved Testability: Separate concerns for easier testing&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The OperationRunnerState pattern isn't just a coding technique, it's a strategic approach to building more robust Flutter applications.Integrating it into your flutter app means you can simplify asynchronous operations while ensuring robust error handling and a better user experience.&lt;/p&gt;

&lt;p&gt;If you’re working on a Flutter app that relies heavily on API calls or other async tasks, adopting this framework will save you time and make your codebase cleaner and more maintainable. 🚀&lt;/p&gt;

&lt;p&gt;Do you have a different approach? Share in the comment section.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>What next after a programming workshop?</title>
      <dc:creator>ASAMOAH MICHAEL</dc:creator>
      <pubDate>Tue, 29 May 2018 09:47:40 +0000</pubDate>
      <link>https://dev.to/iamsirmike/what-next-after-a-programming-workshop-1c9m</link>
      <guid>https://dev.to/iamsirmike/what-next-after-a-programming-workshop-1c9m</guid>
      <description>&lt;p&gt;Let's say you applied  for a programming workshop which usually lasts for few days and got selected. Kindly note that programming workshops are usually an introductory course, basically you'll be exposed to few portion of a particular programming language or framework. Now the big question is 'after that what again?' This is what I have to say...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Keep in touch with your facilitator/mentor/coach: These are the experts who impact or introduce you to the programming language during the workshop. Most people ignore the facilitator/mentor/coach after the workshop. It's very important to keep in touch with them in order to address common problems you face during and after the workshop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practice practice practice: One of the best ways to achieve greatness in programming is continuous practice. Practicing exposes you to more problems which can be forwarded to your facilitator/mentor/coach for solution and guidance, by doing this you stand the chance to grow your skills.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hang out with other coders (Meet-ups): Hanging out with other people who code is a great way to write clean codes. Its also a great way to enhance your skills.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, Volunteer: Life is too short, give back what you've learnt to the society. Engage in volunteering activities to enhance your skills. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
  </channel>
</rss>
