<?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: Mateus 🇧🇷</title>
    <description>The latest articles on DEV Community by Mateus 🇧🇷 (@mateus-ic1101).</description>
    <link>https://dev.to/mateus-ic1101</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%2F2163618%2F6f916135-b658-4c04-b9db-1306d6eb5dcb.jpeg</url>
      <title>DEV Community: Mateus 🇧🇷</title>
      <link>https://dev.to/mateus-ic1101</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mateus-ic1101"/>
    <language>en</language>
    <item>
      <title>Understanding Asynchronous Programming in Dart: Futures and Streams Explained</title>
      <dc:creator>Mateus 🇧🇷</dc:creator>
      <pubDate>Fri, 04 Oct 2024 16:54:06 +0000</pubDate>
      <link>https://dev.to/mateus-ic1101/understanding-asynchronous-programming-in-dart-futures-and-streams-explained-53kk</link>
      <guid>https://dev.to/mateus-ic1101/understanding-asynchronous-programming-in-dart-futures-and-streams-explained-53kk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Understanding Future and Asynchronous Programming in Dart&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The concept of a &lt;code&gt;Future&lt;/code&gt; in Dart represents an operation that will complete at some point in the future, asynchronously. It allows the program to run without blocking other code while waiting for a result.&lt;/p&gt;

&lt;p&gt;In asynchronous operations, the program continues executing normally while the task (such as a data request) runs in the background. Once the task is finished, the &lt;code&gt;Future&lt;/code&gt; returns the result. This prevents the program from "freezing" while waiting.&lt;/p&gt;

&lt;p&gt;Example of asynchronous usage without await:&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() async {
  print('Start of operation');
  setName();
  print('End of the main function');
}

Future&amp;lt;String&amp;gt; setName() =&amp;gt; Future.delayed(Duration(seconds: 3), () {
      print('Operation completed');
      return 'Will 01';
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start of operation
End of the main function
Operation completed
Exited.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous example, the function call to print with the text "End of the main function" was executed before the print statement inside the setName() function. This happened because Dart's execution model is based on a single-threaded event loop with an asynchronous non-blocking nature. When the setName() function is called, it returns a Future immediately, and the Future.delayed operation is scheduled to run after a 3-second delay. However, the main() function does not wait for this delayed operation to complete before continuing its execution. As a result, the next print statement ("End of the main function") is executed right away.&lt;/p&gt;

&lt;p&gt;Technically, this behavior is governed by the event loop and the concept of asynchronous execution. When the Future.delayed is invoked, it schedules a task to be completed after 3 seconds but doesn't block the current thread. This allows Dart to continue executing the remaining code immediately, without waiting for the asynchronous operation to complete.&lt;/p&gt;

&lt;p&gt;To ensure that the main() function waits for the result of setName(), you can use the async and await keywords, which will pause the execution of main() until the Future is resolved.&lt;/p&gt;

&lt;p&gt;Example of asynchronous usage with await:&lt;/p&gt;

&lt;p&gt;We will add this line &lt;code&gt;String name = await setName();&lt;/code&gt; before the last print statement.&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() async {
  print('Start of operation');

  String name = await setName();

  print('End of the main function');
}

Future&amp;lt;String&amp;gt; setName() =&amp;gt; Future.delayed(Duration(seconds: 3), () {
      print('Operation completed');
      return 'Will 01'; 
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start of operation
Operation completed
End of the main function

Exited.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of await in the line &lt;code&gt;String name = await setName();&lt;/code&gt; causes the main() function to pause execution until the setName() function completes and returns a value. This is why the order of output changes compared to the previous example. When await is used, the program waits for the asynchronous operation to finish before proceeding, ensuring that the statement print('End of the main function'); is executed only after the Operation completed message is printed. This reflects Dart's asynchronous programming model, where await allows for more readable and sequential-looking code while still handling operations that take time to complete.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Understanding Streams in Dart&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Dart, a Stream is a sequence of asynchronous events or data that can be listened to. Streams are useful for handling data that arrives over time, such as user input, web requests, or other asynchronous operations.&lt;/p&gt;

&lt;p&gt;A StreamController is an object that allows you to create a stream and control its input. It provides methods to add data to the stream and manage its lifecycle. You can think of it as a bridge between producing and consuming asynchronous data.&lt;/p&gt;

&lt;p&gt;Example:&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() {
  final StreamController&amp;lt;String&amp;gt; controller = StreamController&amp;lt;String&amp;gt;();

  controller.stream.listen((data) {
    print('Listener received: $data');
  });

  addDataToStream(controller);

  Future.delayed(Duration(seconds: 5), () {
    controller.close();
    print('Stream closed.');
  });
}

void addDataToStream(StreamController&amp;lt;String&amp;gt; controller) {
  Timer.periodic(Duration(seconds: 1), (timer) {
    if (timer.tick &amp;lt;= 5) {
      controller.sink.add('Data item ${timer.tick}');
    } else {
      timer.cancel();
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Listener received: Data item 1
Listener received: Data item 2
Listener received: Data item 3
Listener received: Data item 4
Listener received: Data item 5
Stream closed.

Exited.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code demonstrates how to use a StreamController in Dart to manage data streams. A StreamController allows you to produce and listen to data events. In this example, the controller is created to handle a stream of String data.&lt;/p&gt;

&lt;p&gt;The listener is attached to the stream using controller.stream.listen(), which listens for incoming data. Every time new data is added to the stream, the listener prints it to the console.&lt;/p&gt;

&lt;p&gt;The function addDataToStream is responsible for adding data to the stream periodically. It uses Timer.periodic to simulate adding a new data item every second for 5 seconds. The data is sent into the stream via controller.sink.add().&lt;/p&gt;

&lt;p&gt;After 5 seconds, the stream is closed using controller.close(). This ensures no more data can be added to or received from the stream. The stream closure is also confirmed with a message printed to the console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understanding Futures and Streams is essential for effective asynchronous programming in Dart. By mastering these concepts, you empower yourself to build responsive and efficient applications that can handle complex data flows seamlessly. As you integrate these patterns into your development practice, I invite you to share your insights and experiences.&lt;/p&gt;

&lt;p&gt;Your feedback is invaluable! If you have suggestions for improvements, questions, or if you identify any inaccuracies, please don’t hesitate to reach out.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating a REST API in Flutter with Stream: An Alternative to setState</title>
      <dc:creator>Mateus 🇧🇷</dc:creator>
      <pubDate>Thu, 03 Oct 2024 19:50:24 +0000</pubDate>
      <link>https://dev.to/mateus-ic1101/creating-a-rest-api-in-flutter-with-stream-an-alternative-to-setstate-2mph</link>
      <guid>https://dev.to/mateus-ic1101/creating-a-rest-api-in-flutter-with-stream-an-alternative-to-setstate-2mph</guid>
      <description>&lt;p&gt;This is the first post on my profile, and I will talk about streams in Flutter with an example of using them to consume data from an API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a stream and how does it work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Dart, a Stream is a way to handle asynchronous data over time, similar to an event pipeline. It allows you to listen to data as it becomes available, making it perfect for scenarios where you expect multiple values over time, like receiving API responses or handling user input.&lt;/p&gt;

&lt;p&gt;Instead of waiting for a single value (like with Future), Stream emits a sequence of values, either one after the other (for example, real-time data from a REST API) or intermittently. You can "subscribe" to a stream using a listener, and each time a new value arrives, the listener triggers a function. This makes streams a powerful alternative to setState, allowing your UI to react dynamically to changes without manual state updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we will create a new Flutter project. Use the following command to create the project with the name app_stream_api_users:&lt;br&gt;
&lt;code&gt;flutter create app_stream_api_users&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we will install the package to make the API call. The package will be http. To add it to your project, use the following command:&lt;br&gt;
&lt;code&gt;flutter pub add http&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll create a class to handle the API call. In the example, I used Dart's native call method, which allows you to execute the class simply by instantiating it, without needing to specify a method name.&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:app_stream_api_users/dto/user_dto.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

class UserHttp {
  final String apiUrl = 'https://reqres.in/api/users';

  Future&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt; call() async {
    final response = await http.get(Uri.parse('$apiUrl'));

    if (response.statusCode == 200) {
      final List&amp;lt;dynamic&amp;gt; jsonData = jsonDecode(response.body)['data'];
      return jsonData.map((user) =&amp;gt; UserDTO.fromJson(user)).toList();
    } else {
      throw Exception('Failed to load users');
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will create a Data Transfer Object (DTO), which is a concept similar to a model. The purpose of the DTO is to represent the data structure we will work with when consuming data from the API. It will help us efficiently manage the data we receive, making it easier to analyze and use throughout our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserDTO {
  final int id;
  final String email;
  final String firstName;
  final String lastName;
  final String avatar;

  UserDTO({
    required this.id,
    required this.email,
    required this.firstName,
    required this.lastName,
    required this.avatar,
  });

  factory UserDTO.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) {
    return UserDTO(
      id: json['id'],
      email: json['email'],
      firstName: json['first_name'],
      lastName: json['last_name'],
      avatar: json['avatar'],
    );
  }

  Map&amp;lt;String, dynamic&amp;gt; toJson() {
    return {
      'id': id,
      'email': email,
      'first_name': firstName,
      'last_name': lastName,
      'avatar': avatar,
    };
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I won’t create many files. I will place the following code directly in the &lt;code&gt;main.dart&lt;/code&gt;:&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:async';
import 'package:app_stream_api_users/dto/user_dto.dart';
import 'package:app_stream_api_users/http/get_all_users_http.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter App Stream',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter App Stream'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State&amp;lt;MyHomePage&amp;gt; createState() =&amp;gt; _MyHomePageState();
}

class _MyHomePageState extends State&amp;lt;MyHomePage&amp;gt; {
  final StreamController&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt; _controllerUser =
      StreamController&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;.broadcast();

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

  @override
  void dispose() {
    super.dispose();
    _controllerUser.close();
  }

  void getUsers() async {
    final UserHttp http = UserHttp();
    List&amp;lt;UserDTO&amp;gt; users = await http();
    _controllerUser.add(users);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: StreamBuilder&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;(
          stream: _controllerUser.stream,
          initialData: [],
          builder: (context, snapshot) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: &amp;lt;Widget&amp;gt;[
                const Text(
                  'The current value is:',
                ),
                StreamBuilder&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;(
                  stream: _controllerUser.stream,
                  initialData: [], // Começa com uma lista vazia
                  builder: (context, snapshot) {
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      return const CircularProgressIndicator(); // Mostra um loading enquanto carrega
                    } else if (snapshot.hasError) {
                      return const Text('Error loading users');
                    } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
                      return const Text('No users found');
                    } else {
                      final users = snapshot.data!;
                      return Expanded(
                        child: ListView.builder(
                          itemCount: users.length,
                          itemBuilder: (context, index) {
                            final UserDTO user = users[index];
                            return ListTile(
                              leading: CircleAvatar(
                                backgroundImage: NetworkImage(user.avatar),
                              ),
                              title: Text('${user.firstName} ${user.lastName}'),
                              subtitle: Text(user.email),
                            );
                          },
                        ),
                      );
                    }
                  },
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of the code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, we create our StreamController, which will be typed with the data returned from our API. At the end, the broadcast() function is used, which allows multiple listeners to subscribe to the stream simultaneously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final StreamController&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt; _controllerUser =
      StreamController&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;.broadcast();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create the function for our &lt;code&gt;StreamController&lt;/code&gt; to receive data from the API, and we place it in &lt;code&gt;initState&lt;/code&gt;, which is the method called to execute initialization tasks that are essential for the widget's functionality, allowing us to run code before the &lt;code&gt;build()&lt;/code&gt; method. We close the &lt;code&gt;StreamController&lt;/code&gt; after the widget is destroyed to prevent memory leaks. This is done in the &lt;code&gt;dispose&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
  void initState() {
    super.initState();
    getUsers();
  }

  @override
  void dispose() {
    super.dispose();
    _controllerUser.close();
  }

  void getUsers() async {
    final UserHttp http = UserHttp();
    List&amp;lt;UserDTO&amp;gt; users = await http();
    _controllerUser.add(users);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, the &lt;code&gt;StreamBuilder&lt;/code&gt; listens to the &lt;code&gt;_controllerUser&lt;/code&gt; stream and updates the UI with the latest user data. It handles loading states, errors, and empty data gracefully. If there are users, it displays them in a scrollable list with their avatars and details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StreamBuilder&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;(
          stream: _controllerUser.stream,
          initialData: [],
          builder: (context, snapshot) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: &amp;lt;Widget&amp;gt;[
                const Text(
                  'The current value is:',
                ),
                StreamBuilder&amp;lt;List&amp;lt;UserDTO&amp;gt;&amp;gt;(
                  stream: _controllerUser.stream,
                  initialData: [], // Começa com uma lista vazia
                  builder: (context, snapshot) {
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      return const CircularProgressIndicator(); // Mostra um loading enquanto carrega
                    } else if (snapshot.hasError) {
                      return const Text('Error loading users');
                    } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
                      return const Text('No users found');
                    } else {
                      final users = snapshot.data!;
                      return Expanded(
                        child: ListView.builder(
                          itemCount: users.length,
                          itemBuilder: (context, index) {
                            final UserDTO user = users[index];
                            return ListTile(
                              leading: CircleAvatar(
                                backgroundImage: NetworkImage(user.avatar),
                              ),
                              title: Text('${user.firstName} ${user.lastName}'),
                              subtitle: Text(user.email),
                            );
                          },
                        ),
                      );
                    }
                  },
                ),
              ],
            );
          },
        ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>flutter</category>
      <category>dart</category>
      <category>api</category>
      <category>stream</category>
    </item>
  </channel>
</rss>
