<?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>Forem: Giuseppe Vetri</title>
    <description>The latest articles on Forem by Giuseppe Vetri (@gvetri).</description>
    <link>https://forem.com/gvetri</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%2F124654%2F193e9044-4d82-49e2-be75-1b9559f6294c.jpeg</url>
      <title>Forem: Giuseppe Vetri</title>
      <link>https://forem.com/gvetri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gvetri"/>
    <language>en</language>
    <item>
      <title>Cloudbuild with Android - Using Encrypted Environment Variables</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Thu, 30 Apr 2020 18:48:02 +0000</pubDate>
      <link>https://forem.com/codingpizza/cloudbuild-with-android-using-encrypted-environment-variables-15ml</link>
      <guid>https://forem.com/codingpizza/cloudbuild-with-android-using-encrypted-environment-variables-15ml</guid>
      <description>&lt;p&gt;Hi there! At my current work, we had a problem with our CI/CD, and we started to look for alternatives. We checked out various platforms like CircleCI, Bitrise, and others. Still, the process to ask the upper-level management to add this as providers was a bit slow and tedious so, since we already had GCP as a provider, we decided to try GCP Cloudbuild.&lt;/p&gt;

&lt;p&gt;Cloudbuild is an infrastructure that allows you to run builds for your projects. The price was reasonable, so we decided to start investing time on it to move our Android CI/CD all to cloudbuild.&lt;/p&gt;

&lt;p&gt;As first we started looking for some previous experience on the internet and found two excellent articles about it, those articles will be linked below. Nevertheless, those articles required a certain knowledge of Docker, CloudBuild, and other technologies that I didn't have.&lt;/p&gt;

&lt;p&gt;So I started learning about it to understand these articles better. What I wanted to achieve first was to read an encrypted environment variable. With this goal in mind, I started my quest.&lt;/p&gt;

&lt;p&gt;Note: Articles in which this post is based.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ryanharter.com/blog/cloud-build/"&gt;&lt;strong&gt;https://ryanharter.com/blog/cloud-build/&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/dailymotion/run-your-android-ci-in-google-cloud-build-2487c8b70ccf"&gt;&lt;strong&gt;https://medium.com/dailymotion/run-your-android-ci-in-google-cloud-build-2487c8b70ccf&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First, let's enable GCP KMS
&lt;/h2&gt;

&lt;p&gt;What we need to do first is go to the GCP console, create our new project, and enable the KMS. You must go to Security → Cryptographic Keys.&lt;/p&gt;

&lt;p&gt;Note: KMS stands for Key Management Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-Y4E0LO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-Y4E0LO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image1.png" alt="Sidebar menu which shows the cloud build KMS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Keyring and a Criptokey
&lt;/h2&gt;

&lt;p&gt;A Keyring can hold various CryptoKeys. To create a Keyring, you need to use the following command:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;"yourkeyringname" is the name of your Keyring, and you should replace it for your what suits best for you, and the flag --location=global means that this Keyring is available in all regions of your project.&lt;/p&gt;

&lt;p&gt;Now that we already created a Keyring, let's create our new CryptoKey, for that we're going to use the next command.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;"KEYNAME" is the name of the key you want to create, and the--keyring flag is to indicate to which Keyring it's going to belong since we're using as an example "yourkeyringname" it will belong to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypting the variable
&lt;/h2&gt;

&lt;p&gt;To encrypt our variable, we must store it in a plain text file and then create a ciphertext file from that one. For that, we're going to use the next command.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;What this does for you is to encrypt your my_variable.txt file and convert it to my_variable_encrypted.txt using your Keyring and your cryptokey. After that, you need to create a base64 from your encrypted variable, and that can be achieved using the next command:&lt;/p&gt;

&lt;p&gt;If you're using &lt;strong&gt;macOS&lt;/strong&gt; you can use:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;In &lt;strong&gt;Linux&lt;/strong&gt;, the command is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;The result of this process is going to be something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is an example. Your base64 is not going to be the same.&lt;/p&gt;

&lt;p&gt;Now let's store this base64 until we finish the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our AndroidBuilder
&lt;/h2&gt;

&lt;p&gt;In this step, we're going to create our new Docker Image and pass to it our secret as a Build Argument. If you never created a Dockerfile before, probably you want to learn about it before continuing with this topic.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;What we do in this Dockerfile is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obtain the javac builder from GCR (Google Container Registry).&lt;/li&gt;
&lt;li&gt;Update the system.&lt;/li&gt;
&lt;li&gt;Download the dependencies.&lt;/li&gt;
&lt;li&gt;Set our "build arg" with the name SECRET.&lt;/li&gt;
&lt;li&gt;Set the ANDROID_HOME as an environment variable.&lt;/li&gt;
&lt;li&gt;Copy our gradle-build script(This is a little script that helps us to store the gradle cache so the subsequent builds can be faster).&lt;/li&gt;
&lt;li&gt;Download the android sdk tools, set our tools as an environment variable, and finally install the Android SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the gradle-build script that is mentioned in the Dockerfile.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This Dockerfile and gradle-build script are based on &lt;a href="https://medium.com/dailymotion/run-your-android-ci-in-google-cloud-build-2487c8b70ccf"&gt;this&lt;/a&gt; article that helped me a lot. I only added a few instructions, the latest android platform, build-tools, platform-tools, and the &lt;code&gt;ARG SECRET&lt;/code&gt; line.&lt;/p&gt;

&lt;p&gt;If you're a more advanced user of Docker and GCP, you can use the community cloud builder, which can be found &lt;strong&gt;&lt;a href="https://github.com/GoogleCloudPlatform/cloud-builders-community/tree/master/android"&gt;here&lt;/a&gt;&lt;/strong&gt;. I wanted a simpler proof of concept, so the previous one was the one that fit best for me.&lt;/p&gt;

&lt;p&gt;As the last part of this step, we're going to create a cloudbuild.yaml, which is going to build our container and upload it to the Google Container Registry. In this cloudbuild.yaml file, we're going to execute a command which builds the container. There is where we're going to run our Android project. In this cloudbuild.yaml, we pass our secret and use the base64 that we generated before, here's how it's going to look.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;In this file, we're building a Docker container and passing our secret as build arg. You can see that we're using a double dollar sign to escape the cloudbuild substitutions, which are, for example, the $PROJECT_ID, then we're declaring that we're going to use the secret at the end of our cloudbuild.yaml. Remember to replace "yourprojectname," "yourkeyring," "yourcryptokey" and your base64 in the previous file.&lt;/p&gt;

&lt;p&gt;Finally, we use the following command to build it and send it to the Container Registry.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: If you're getting an error because the Container Registry doesn't have permission to decrypt you must go to your GCP console, Select Cloudbuild, go to configuration and copy your service account email, go to Security → Cryptographic keys → Select your key → Click the add member button in the right panel, add it as a member and select the role of decrypt cryptographic keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cloudbuild file in our android project
&lt;/h2&gt;

&lt;p&gt;Now that we created our container to run our Android project, what we're going to do is to create the cloudbuild file of our Android Project.&lt;/p&gt;

&lt;p&gt;First, we're going to create a couple of GCP Storage Bucket, and the Storage Buckets are object storages provided by the Google Cloud Platform. In other words, it helps us to store things. In our case, it will be helpful for our Gradle cache and apks.&lt;/p&gt;

&lt;p&gt;To create it, we're going to open up the terminal and type the next command.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;In our cloudbuild.yaml we're going to describe the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy our cache into our GCP Storage Bucket using the gsutil image from Google Container Registry. The GCP provides this image, so we don't have to build our own.&lt;/li&gt;
&lt;li&gt;Run a &lt;strong&gt;KtLintCheck&lt;/strong&gt; task on our previously created AndroidBuilder.&lt;/li&gt;
&lt;li&gt;Run a &lt;strong&gt;detekt&lt;/strong&gt; task in our AndroidBuilder.&lt;/li&gt;
&lt;li&gt;Run our &lt;strong&gt;unit&lt;/strong&gt; test always on our AndroidBuilder.&lt;/li&gt;
&lt;li&gt;Assemble our Apk.&lt;/li&gt;
&lt;li&gt;Store the cache.&lt;/li&gt;
&lt;li&gt;Store our apks in a storage bucket.&lt;/li&gt;
&lt;li&gt;Finally, we set the timeout for the build to 1200 seconds.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;Note: Ktlint is a linting tool for Kotlin, and &lt;strong&gt;&lt;a href="https://goobar.io/2019/07/25/adding-ktlint-to-your-kotlin-project/"&gt;you can read more about it in this awesome article&lt;/a&gt;&lt;/strong&gt; by Nate Ebel. On the other hand, detekt is a static code analysis tool for Kotlin, and you can read more about it &lt;a href="https://proandroiddev.com/detecting-kotlin-code-smells-with-detekt-e79c52a35faf"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the triggers.
&lt;/h2&gt;

&lt;p&gt;Now we want to set-up the build triggers, so each time we push a branch, we can run our build to verify that everything is fine. To do this, we need to go to &lt;a href="http://console.google.com/"&gt;console.google.com&lt;/a&gt;, select our project, go to the navigation menu, select cloud build, triggers, connect our repository if you haven't already, and then click the create trigger option. It looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w98HQ_TL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w98HQ_TL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image2.png" alt="Create Trigger in GCP form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a trigger that we want to run when a new feature branch is pushed to the repo. To test it, you need to push a new branch to the repo and check the GCP console history. If everything went well, you're going to see something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mgROKJyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mgROKJyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/04/image3.png" alt="Successfully worked trigger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also try your builds locally using &lt;strong&gt;cloud-build-local&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test your build locally
&lt;/h2&gt;

&lt;p&gt;Pushing to GitHub to trigger the build can be annoying and a slow process. If you want to test your build, you can test it in your computer using cloudbuild local and running the following command:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You need to install first cloud-build-local with the following commands.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;You can read more about it &lt;strong&gt;&lt;a href="https://cloud.google.com/cloud-build/docs/build-debug-locally"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do we go from here
&lt;/h2&gt;

&lt;p&gt;This was a proof of concept that I used to learn new things and to propose it to the DevOps team, in my job, I wanted to help them to help our Android team as I mentioned before this can be hugely improved so feel free to improve it or to use the community cloudbuilder if that fits your needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://ryanharter.com/"&gt;Ryan Harter&lt;/a&gt;&lt;/strong&gt; has a series in which he talks about how to increment the build numbers and how to store the build cache. If you want to go even further, play around with the community builders.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can take away from this
&lt;/h2&gt;

&lt;p&gt;If you're looking for an alternative to circleCI, bitrise, or others, and you're not afraid of a terminal and learning new things (Assuming you're like me and didn't know anything about cloudbuild) cloudbuild is cool. Surely it doesn't have the beautiful UI/UX of one Continuous Integration provider. But it does very well the job. So it depends on your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;If you have any questions, suggestions, or improvements, please leave a comment 😄. You can also reach me via Twitter &lt;a href="http://www.twitter.com/gvetri18"&gt;@gvetri18&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>cloudbuild</category>
      <category>gcp</category>
    </item>
    <item>
      <title>📸 Taking a picture and selecting from gallery in Flutter</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Thu, 05 Mar 2020 20:29:29 +0000</pubDate>
      <link>https://forem.com/codingpizza/taking-a-picture-and-selecting-from-gallery-in-flutter-2314</link>
      <guid>https://forem.com/codingpizza/taking-a-picture-and-selecting-from-gallery-in-flutter-2314</guid>
      <description>&lt;p&gt;Hi there! I've been working in an App that requires to take a picture from the app or pick it from the gallery. And here's what I learned about it. There are many ways to take a photo using the camera. This time we're going to use the ImagePicker plugin.&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's start with the dependencies.
&lt;/h1&gt;

&lt;p&gt;As the first step, we need to add new plugins to our dependencies. In our &lt;strong&gt;pubspec.yaml&lt;/strong&gt; we're going to add the next plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Camera&lt;/strong&gt; which helps us to work with the device's cameras.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path_provider&lt;/strong&gt; gives us the correct path to store images in our devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;image_picker&lt;/strong&gt; helps us with the photo selected from the gallery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After we add it to our &lt;strong&gt;pubspec.yaml&lt;/strong&gt;, it's going to look like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: fluttercamera
description: A Flutter project that takes a picture and shows the preview.
version: 1.0.0+1

environment:
  sdk: "&amp;gt;=2.1.0 &amp;lt;3.0.0"

dependencies:
  flutter:
    sdk: flutter
  camera:
  path_provider:
  path:
  image_picker:

  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:

  uses-material-design: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Adding a min Android SDK.
&lt;/h2&gt;

&lt;p&gt;The Flutter camera plugin only works with an sdk 21 or higher in Android. So we need to open our build.gradle file located at &lt;code&gt;android/app/build.gradle&lt;/code&gt; and search for the line &lt;code&gt;minSdkVersion&lt;/code&gt;. Lastly, we need to upgrade our min sdk version from 16 to 21. If you don't know anything about android development, this made the app available only from Android OS Lollipop or later.&lt;/p&gt;

&lt;p&gt;This is how it should look like after doing that change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_2020-02-18_20-25-59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_2020-02-18_20-25-59.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's create our first screen!
&lt;/h2&gt;

&lt;p&gt;Let's create our &lt;strong&gt;PhotoPreviewScreen&lt;/strong&gt;, which is a StatefulWidget. In the beginning, it should look like this.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PhotoPreviewScreen extends StatefulWidget {
  @override
  _PhotoPreviewScreenState createState() =&amp;gt; _PhotoPreviewScreenState();
}

class _PhotoPreviewScreenState extends State&amp;lt;PhotoPreviewScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

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

&lt;/div&gt;

&lt;p&gt;Now we're going to create a &lt;strong&gt;Scaffold&lt;/strong&gt; with a centered column that is going to show our image preview after we pick it from the gallery or take a picture from the camera. As of the last step, we're going to add a &lt;strong&gt;floatingActionButton&lt;/strong&gt;, which is going to show the selection dialog.&lt;/p&gt;

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

class _PhotoPreviewScreenState extends State&amp;lt;PhotoPreviewScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &amp;lt;Widget&amp;gt;[
            _setImageView()
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _showSelectionDialog(context);
        },
        child: Icon(Icons.camera_alt),
      ),
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Great! Now you're probably asking what the &lt;strong&gt;_setImageView()&lt;/strong&gt; and the &lt;strong&gt;_showSelectionDialog(context)&lt;/strong&gt; do. The &lt;strong&gt;_setImageView() is&lt;/strong&gt; a method that returns a Widget in case the Image we pick from the gallery or take from the camera is null. We're returning a Text Widget that has the following text "Please select a picture."&lt;/p&gt;

&lt;p&gt;The*&lt;em&gt;_showSelectionDialog(context)&lt;/em&gt;* is going to show a dialog with two options, take an image from the gallery or the camera. Let's start creating this one. This method should use the function showDialog() and pass to it the context and a builder who is going to create an AlertDialog with a title and two options.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;AlertDialog&lt;/strong&gt; constructor, we're going to pass as content a &lt;strong&gt;SingleChildScrollView&lt;/strong&gt; which is a Widget that helps us to scroll the list, as a child of this Widget we're going to pass a &lt;strong&gt;ListBody&lt;/strong&gt; with two children, those children must be a &lt;strong&gt;GestureDetector&lt;/strong&gt; to detect when the user touches the text.&lt;/p&gt;

&lt;p&gt;Each &lt;strong&gt;GestureDetector&lt;/strong&gt; child is going to be a Text Widget with the "Gallery" text and "Camera" text, respectively, and each onTap() method is going to be &lt;strong&gt;_openGallery()&lt;/strong&gt; and &lt;strong&gt;_openCamera()&lt;/strong&gt;. Methods that we're going to create in a while. Your &lt;strong&gt;_showSelectionDialog(context)&lt;/strong&gt; should look like this.&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; _showSelectionDialog(BuildContext context) {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
              title: Text("From where do you want to take the photo?"),
              content: SingleChildScrollView(
                child: ListBody(
                  children: &amp;lt;Widget&amp;gt;[
                    GestureDetector(
                      child: Text("Gallery"),
                      onTap: () {
                        _openGallery(context);
                      },
                    ),
                    Padding(padding: EdgeInsets.all(8.0)),
                    GestureDetector(
                      child: Text("Camera"),
                      onTap: () {
                        _openCamera(context);
                      },
                    )
                  ],
                ),
              ));
        });
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now your app should show a Dialog like this one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_1582056613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_1582056613.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's use that plugin.
&lt;/h2&gt;

&lt;p&gt;Now let's add the logic to our &lt;strong&gt;_openGallery(context)&lt;/strong&gt; method. What we're going to do first is create a field called imageFile, which is going to be a File object in our &lt;strong&gt;_LandingScreenState&lt;/strong&gt; class. After creating that, we're going to use the ImagePicker function &lt;strong&gt;ImagePicker.pickImage()&lt;/strong&gt; passing to it the enum*&lt;em&gt;&lt;code&gt;ImageSource.gallery&lt;/code&gt;&lt;/em&gt;* This function is asynchronous, so we're going to add the reserved keywords async and await, later we're going to save that variable and assign it to our property. As our last step, we're going to call the &lt;strong&gt;setState()&lt;/strong&gt; method to notify that the state has changed.&lt;/p&gt;

&lt;p&gt;The function &lt;strong&gt;_openGallery(context)&lt;/strong&gt; should look like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void _openGallery(BuildContext context) async {
    var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
    this.setState(() {
      imageFile = picture;
    });
    Navigator.of(context).pop();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The _openCamera(context) function it's almost the same. The only thing we need to change is the source, instead of ImageSource.gallery we're going to use ImageSource.camera. This simplicity is what I most liked from this plugin, that was so simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing the preview
&lt;/h2&gt;

&lt;p&gt;Remember the &lt;strong&gt;_setImageView()&lt;/strong&gt; that was at the beginning? Well, we're going to verify that the field imageField is not null to return an &lt;strong&gt;Image&lt;/strong&gt; Widget. If the image field is null, we're going to return a &lt;strong&gt;Text&lt;/strong&gt; Widget.&lt;/p&gt;

&lt;p&gt;This is the result.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Widget _setImageView() {
    if (imageFile != null) {
      return Image.file(imageFile, width: 500, height: 500);
    } else {
      return Text("Please select an image");
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is how your app should look after you select a image from the gallery. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_1582057892.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F02%2FScreenshot_1582057892.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;I hope you liked it! If you're interested in more Flutter/Dart articles, you can follow me on social and say hello!.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.instagram.com/codingpizza" rel="noopener noreferrer"&gt;Instagram.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://twitter.com/coding__pizza" rel="noopener noreferrer"&gt;Twitter.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://eepurl.com/gcIboL" rel="noopener noreferrer"&gt;😄 &lt;strong&gt;Click here to join the newsletter&lt;/strong&gt; &lt;/a&gt;
&lt;/h2&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
    </item>
    <item>
      <title>📸 Como tomar una foto con Flutter o elegir una foto de la galería.</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Thu, 05 Mar 2020 20:28:51 +0000</pubDate>
      <link>https://forem.com/codingpizza/como-tomar-una-foto-con-flutter-o-elegir-una-foto-de-la-galeria-deh</link>
      <guid>https://forem.com/codingpizza/como-tomar-una-foto-con-flutter-o-elegir-una-foto-de-la-galeria-deh</guid>
      <description>&lt;p&gt;¡Hola! Ultimamente he estado trabajando en una app que requiere tomar una foto desde la app o de la galeria y mostrarla al usuario. He aprendido un par de cosas implementando esta feature y he querido compartirlo por acá. Existen varias formas de tomar una foto utilizando la cámara pero en esta oportunidad vamos a utilizar el &lt;strong&gt;imagePicker&lt;/strong&gt; plugin.&lt;/p&gt;

&lt;h1&gt;
  
  
  Empecemos por las dependencias.
&lt;/h1&gt;

&lt;p&gt;Como primer paso, vamos a agregar los plugins a nuestras dependencias. Abrimos nuestro &lt;strong&gt;pubspec.yaml&lt;/strong&gt; y agregamos los siguientes plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;camera:&lt;/strong&gt; Este plugin nos ayudará a trabajar con las cámaras de los dispositivos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path_provider:&lt;/strong&gt; Este plugin nos proporciona el &lt;strong&gt;path&lt;/strong&gt; correcto para saber donde almacenar las imagenes en nuestro dispositivo, ya que cambian entre una plataforma y otra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;image_picker&lt;/strong&gt; este nos ayuda a seleccionar una foto de la galería.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despues de agregar estos plugins nuestro &lt;strong&gt;pubspec.yaml&lt;/strong&gt; debería verse así.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: fluttercamera
description: A Flutter project that takes a picture and shows the preview.
version: 1.0.0+1

environment:
  sdk: "&amp;gt;=2.1.0 &amp;lt;3.0.0"

dependencies:
  flutter:
    sdk: flutter
  camera:
  path_provider:
  path:
  image_picker:

  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:

  uses-material-design: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Aumentamos la versión minima de Android
&lt;/h2&gt;

&lt;p&gt;El plugin de &lt;strong&gt;camera&lt;/strong&gt; en Flutter solo funciona con sdk 21 en adelante en Android, lo que quiere decir que solo dispositivos Android con sistema operativo &lt;strong&gt;Lollipop&lt;/strong&gt; o superior pueden utilizar una app con este plugin.&lt;/p&gt;

&lt;p&gt;Para esto vamos a abrir el archivo build.gradle ubicado en &lt;code&gt;android/app/build.gradle&lt;/code&gt; y buscar la linea que dice "&lt;code&gt;minSdkVerrsion&lt;/code&gt;". Finalmente cambiamos la versión de 16 a 21.&lt;/p&gt;

&lt;p&gt;Luego de cambiar la versión debería verse así &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QpD-TLHV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_2020-02-18_20-25-59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QpD-TLHV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_2020-02-18_20-25-59.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ¡Creemos nuestro primer Screen!
&lt;/h2&gt;

&lt;p&gt;Para empezar vamos a crear un &lt;strong&gt;StatefulWidget&lt;/strong&gt; llamado &lt;strong&gt;PhotoPreviewScreen&lt;/strong&gt;. Debería verse de esta manera.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PhotoPreviewScreen extends StatefulWidget {
  @override
  _PhotoPreviewScreenState createState() =&amp;gt; _PhotoPreviewScreenState();
}

class _PhotoPreviewScreenState extends State&amp;lt;PhotoPreviewScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

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

&lt;/div&gt;

&lt;p&gt;Ahora, vamos a crear un &lt;strong&gt;Scaffold&lt;/strong&gt; con un widget Column centrado el cual va a mostrar una vista previa de nuestra imagen después que tomemos una foto o la seleccionemos de la galería. Y como paso final vamos a agregar un &lt;strong&gt;floatingActionButton&lt;/strong&gt;, que al tocar nos mostrará un dialogo con las opciones para elegir una foto de la galería o desde la cámara.&lt;/p&gt;

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

class _PhotoPreviewScreenState extends State&amp;lt;PhotoPreviewScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &amp;lt;Widget&amp;gt;[
            _setImageView()
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _showSelectionDialog(context);
        },
        child: Icon(Icons.camera_alt),
      ),
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;¡Genial! Ahora seguramente te estés preguntando qué hace el &lt;strong&gt;_setImageView()&lt;/strong&gt; y el &lt;strong&gt;_showSelectionDialog(Context).&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;_setImageView()&lt;/strong&gt; es un método que devuelve un Image Widget en caso de que la imagen obtenida no sea nula, de lo contrarío devolverá un Text Widget con un mensaje de Error. El método &lt;strong&gt;_showSelectionDialog(Context)&lt;/strong&gt; muestra un dialogo con dos opciones, seleccionar una imagen de galería o de la cámara. &lt;/p&gt;

&lt;p&gt;Empecemos creando el último, este método debe usar la función &lt;strong&gt;showDialog()&lt;/strong&gt; y pasarle el &lt;strong&gt;Context&lt;/strong&gt; y un &lt;strong&gt;Builder&lt;/strong&gt; el cual va crear un AlertDialog con un titulo y dos opciones.&lt;/p&gt;

&lt;p&gt;En el constructor del &lt;strong&gt;AlertDialog&lt;/strong&gt;, vamos a pasar como contenido un &lt;strong&gt;SingleChildScrollView&lt;/strong&gt; el cual es un Widget que nos ayudará a hacer scroll en la lista, y como &lt;strong&gt;child&lt;/strong&gt; de este Widget vamos a pasarle un &lt;strong&gt;ListBody&lt;/strong&gt; con dos &lt;strong&gt;GestureDetector&lt;/strong&gt; como hijos para detectar cuándo el usuario ha tocado el texto.&lt;/p&gt;

&lt;p&gt;Cada &lt;strong&gt;GestureDetector&lt;/strong&gt; va a tener un Text Widget con el texto "Galería" y "Cámara" respectivamente. Y cada Text widget tambíen tendrá como parámetro de su función onTap el método &lt;strong&gt;_openGallery()&lt;/strong&gt; y &lt;strong&gt;openCamera()&lt;/strong&gt; segun corresponda.  Estos métodos los crearemos más adelante. Al terminar el método &lt;strong&gt;_showSelectionDialog(context)&lt;/strong&gt; estará así.&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; _showSelectionDialog(BuildContext context) {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
              title: Text("From where do you want to take the photo?"),
              content: SingleChildScrollView(
                child: ListBody(
                  children: &amp;lt;Widget&amp;gt;[
                    GestureDetector(
                      child: Text("Gallery"),
                      onTap: () {
                        _openGallery(context);
                      },
                    ),
                    Padding(padding: EdgeInsets.all(8.0)),
                    GestureDetector(
                      child: Text("Camera"),
                      onTap: () {
                        _openCamera(context);
                      },
                    )
                  ],
                ),
              ));
        });
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ahora al tocar nuestro FloatingActionButton debería mostrar un Dialog como este.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XtfRMSiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_1582056613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XtfRMSiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_1582056613.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ahora a utilizar el plugin ImagePicker
&lt;/h2&gt;

&lt;p&gt;Ahora vamos a agregarle la lógica a nuestro método &lt;strong&gt;_openGallery(context).&lt;/strong&gt; Lo primero que vamos a hacer es crear un &lt;strong&gt;Field&lt;/strong&gt; llamado imageFile, el cual va a ser una variable de tipo &lt;strong&gt;File&lt;/strong&gt; en nuestro &lt;strong&gt;_LandingScreenState.&lt;/strong&gt; Luego vamos a utilizar la función del &lt;strong&gt;ImagePicker&lt;/strong&gt;, llamada &lt;strong&gt;pickImage()&lt;/strong&gt; y le vamos a pasar como parámetro el enum &lt;strong&gt;&lt;a href="http://imagesource.gallery"&gt;ImageSource.gallery&lt;/a&gt;.&lt;/strong&gt; Esta función es asíncrona así que vamos a tener que utilizar las palabras reservadas async y await. Luego vamos a almacenar esta variable y asignarla a nuestra variable &lt;strong&gt;imageFile&lt;/strong&gt;. Como paso final, vamos a llamar al método &lt;strong&gt;setState()&lt;/strong&gt; para notificar que el &lt;strong&gt;State&lt;/strong&gt; ha cambiado. Y nuestra función deberá verse así. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void _openGallery(BuildContext context) async {
    var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
    this.setState(() {
      imageFile = picture;
    });
    Navigator.of(context).pop();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;La función _openCamera(Context) es casi igual, la unica diferencía que tiene al respecto es que esta utiliza el enum &lt;a href="http://imagesource.camera"&gt;imageSource.camera&lt;/a&gt; en lugar de gallery. Al realizar este cambio tu función de &lt;strong&gt;_openCamera()&lt;/strong&gt; deberá verse así.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void _openCamera(BuildContext context) async {
    var picture = await ImagePicker.pickImage(source: ImageSource.camera);
    this.setState(() {
      imageFile = picture;
    });
    Navigator.of(context).pop();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Previsualización
&lt;/h2&gt;

&lt;p&gt;¿Recuerdas aquella función que mencionamos al principio llamada &lt;strong&gt;_setImageView()?&lt;/strong&gt; Pues no podemos olvidarnos de ella. Para ello vamos a verificar si nuestra variable imageFile es distinta de null. Si lo es, devolvemos un &lt;strong&gt;Image&lt;/strong&gt; Widget con la variable que teniamos almacenada y si aún es nula pues devolvemos un texto que diga que debemos seleccionar una imagen.&lt;/p&gt;

&lt;p&gt;Así se vería la función terminada.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Widget _setImageView() {
    if (imageFile != null) {
      return Image.file(imageFile, width: 500, height: 500);
    } else {
      return Text("Please select an image");
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Así es como se vería la app al final, luego de seleccionar una imagen de la galería.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AA4n9Cz_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_1582057892.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AA4n9Cz_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/02/Screenshot_1582057892.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Eso es todo
&lt;/h2&gt;

&lt;p&gt;Espero que te haya gustado este artículo. Si te interesan mas contenido sobre Flutter o Dart puedes seguirme en las redes sociales.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.instagram.com/codingpizza"&gt;Instagram.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://twitter.com/coding__pizza"&gt;Twitter.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤓Adémas no te pierdas ningun artículo uniendote a mi newsletter
&lt;/h2&gt;

&lt;p&gt;Puedes registrarte haciendo click acá debajo 👇.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://eepurl.com/gcIboL"&gt;😄 &lt;strong&gt;Haz click aquí para unirte a la newsletter&lt;/strong&gt; &lt;/a&gt;
&lt;/h2&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
    </item>
    <item>
      <title>Que es un unit test (Prueba unitaria)</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Tue, 21 Jan 2020 20:11:32 +0000</pubDate>
      <link>https://forem.com/codingpizza/que-es-un-unit-test-prueba-unitaria-2dnk</link>
      <guid>https://forem.com/codingpizza/que-es-un-unit-test-prueba-unitaria-2dnk</guid>
      <description>&lt;p&gt;Hola! Probablemente hayas visto en ofertas de trabajo la siguiente frase, "Experiencia con pruebas unitarias y TDD." Pero si eres como yo y no tienes idea sobre tests, has oído de ellos, sabes que existen y sabes que las buenas compañías lo usan. Pero, ¿qué son y cómo funcionan?&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Empecemos con un test
&lt;/h2&gt;

&lt;p&gt;Cuando alguien de QA (Quality assurance, aquellos que prueban tu app y encuentran fallos que tu no conocías) se acerca a mi y me pregunta si estoy seguro sobre lo que hace mi código, mi respuesta siempre es no, y no es porque no confié en mis habilidades de programación, es porque soy humano y como todo ser humano cometemos errores. Es por esto que empece a aprender sobre testing ya que los test pueden ayudarte a conseguir los errores que vas a introducir en el futuro. &lt;/p&gt;

&lt;p&gt;Un test ayuda a probar algo, en nuestro caso, que nuestro código vaya como lo hemos planeado. Con mis simples palabras podría decir que un test es código que tu escribes para verificar que el código que vas a tener en producción funciona y hace lo que esperas que haga.&lt;/p&gt;

&lt;h2&gt;
  
  
  👩‍💼👨‍💼Unidad
&lt;/h2&gt;

&lt;p&gt;Una unidad es algo individual, digamos que un elemento, muchos elementos pueden crear algo mas grande que ellos. En nuestro caso, una unidad puede ser una clase o una función la cual junto con otras clases u otras funciones pueden crear una app mas compleja.&lt;/p&gt;

&lt;p&gt;Al hacer pruebas de cada una de las unidades estamos haciendo pruebas unitarias.&lt;/p&gt;

&lt;h2&gt;
  
  
  👩‍💼👨‍💼 La prueba unitaria
&lt;/h2&gt;

&lt;p&gt;Digamos que vamos a crear una nueva, nunca hecha, disruptiva app llamada calculadora. En esta app tendremos una función llamada &lt;strong&gt;sum()&lt;/strong&gt;, la cual realiza la suma de dos números. Si lo hacemos en Kotlin, sería:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun sum(int a,int b) : Int {
    return a+a;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Luego nos vamos a crear nuestra UI (Interfaz de usuario) la cual es fantástica y amamos hacer para que quede todo super lindo, pero cundo corremos la app y empezamos a probarla, nos damos cuenta de que la función de suma no funciona. ¿Por qué no funciona? Si los parámetros los he declarado bien y la suma va bien. Créeme, esto ocurre mucho mas de lo que imaginas.&lt;/p&gt;

&lt;p&gt;Y es un problema si tus build times toman cierto tiempo. Ejecutar una compilación que tarde mucho puede romper el estado de concentración en el que te encontrabas, y espero que no seas como yo quien se distrae fácilmente y pierde el foco de que estaba haciendo. Por suerte, las pruebas unitarias pueden ayudarnos a solucionar estos dos problemas ya que los tests se encargan de verificar que el código haga lo que supone que debe hacer y como las pruebas unitarias son mas rápidas que compilar toda la app y probar cada cosa manualmente nos vienen de maravilla. Así que para empezar, vamos a crear nuestro primer test.&lt;/p&gt;

&lt;p&gt;Casi todos los lenguajes tienen un framework para tests. Puedes revisar cual es el framework para test disponibles para tu lenguaje &lt;a href="https://www.notion.so/codingpizza/Que-es-un-unit-test-Prueba-unitaria-47049be52694488e96941d19e1240060#ed90ea4a255d495c82aa9b765271af40"&gt;**aquí&lt;/a&gt;.** En nuestro caso como estoy usando Kotlin, vamos a usar JUnit.&lt;/p&gt;

&lt;p&gt;Una prueba unitaria se parece a esto y por defecto está en la carpeta de tests del proyecto.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @Test
    fun calculator_sum_shouldReturnTheSumBetweenTwoParameters() {
        //Given
        val calculator = Calculator()
        //When
        val result = calculator.sum(2, 1)
        //Then
        assertEquals(3,result)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Analicemos un poco qué contiene este Test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La anotación &lt;code&gt;@Test&lt;/code&gt; que indica que es un Test.&lt;/li&gt;
&lt;li&gt;El nombre de la función que indica &lt;strong&gt;[Unidad_NombreDeLoQueEstamosProbando_ResultadoEsperado]&lt;/strong&gt;, esto en ingles se hace de la siguiente forma: &lt;strong&gt;[Unit_WhatWeAreTesting_ExpectedBehavior].&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;El contenido del test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nuestro test debe seguir el patrón Arrange-Act-Assert (Organizar, actuar y afirmar) o el Given- When-Then (Dado que, cuando, entonces). A mi me gusta el patrón given, when, then debido a que me recuerda mucho a lo que suelo ver en las historias de usuario. Además, si te distraes puedes seguir los pasos y recordar el paso que te falta. Hablemos un poco sobre este patrón.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given: En esta parte del patrón, los objetos que vas a necesitar son creados.&lt;/li&gt;
&lt;li&gt;When: En este paso, llamamos a la función que queremos probar.&lt;/li&gt;
&lt;li&gt;Then: Finalmente, en la ultima sección, hacemos la comprobación para evaluar el resultado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Veamos un ejemplo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NcUnGA21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bj8lz6o69ifd1a17ei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NcUnGA21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bj8lz6o69ifd1a17ei.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En mi caso estoy usando Intellij Idea, en este IDE tengo un botón de play cerca de mi test y al hacerle click podremos ver en la siguiente imagen cómo el test falla.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G3tCrZyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tvaux78n0q94dikrati2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G3tCrZyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tvaux78n0q94dikrati2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuestro test ha fallado porque nuestra función está sumando dos veces el primer parámetro 🤦‍♂. Ahora que ya sabemos qué ocurre podremos cambiar nuestra función y ejecutar de nuevo el test para ver cómo pasa.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun sum(int a,int b) : Int {
    return a+b;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AQsnczSJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8l37t5h0gair3xam8qje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AQsnczSJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8l37t5h0gair3xam8qje.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Increíble. Tengo que admitir que ahora el verde se ha vuelto uno de mis colores favoritos ya que es el color de los tests al pasar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota de Kotlin:&lt;/strong&gt; En Kotlin, podemos utilizar las comillas invertidas como nombre de la función y hacer nuestro Test mas legible!&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test&lt;br&gt;
    fun &lt;code&gt;calculator sum should Return The Sum Between Two Parameters&lt;/code&gt;() {&lt;br&gt;
        //Given&lt;br&gt;
        val calculator = Calculator()&lt;br&gt;
        //When&lt;br&gt;
        val result = calculator.sum(2, 1)&lt;br&gt;
        //Then&lt;br&gt;
        assertEquals(3,result)&lt;br&gt;
    }&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  🔺 La pirámide del testing&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Hemos hablado sobre qué es un unit test, pero hay más tipos de test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit Test, se encargan de probar una unidad en especifico.&lt;/li&gt;
&lt;li&gt;Test de integración, verifica que dos o más unidades estén funcionando juntas correctamente como deberían.&lt;/li&gt;
&lt;li&gt;End to End tests, verifican que todas las unidades están funcionando correctamente. En el caso de android esto incluye probar la UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visto que tenemos varios tipos de test, debemos dividirlos razonablemente. No todos los tests pueden ser End to End o test de integración. Por suerte, hay una imagen que explica muy bien cómo debemos distribuir los tests y se llama la pirámide del testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp3Vn4IR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h6my1l2dgju7rhq8p8mp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp3Vn4IR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h6my1l2dgju7rhq8p8mp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La pirámide del testing fue creada por Mike Cohn en su libro, Succeeding with Agile. Y en este, comenta que los unit test deberían ser la base de la pirámide seguidos por los test de integración y finalmente los End to End.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤓 Otros beneficios del testing
&lt;/h2&gt;

&lt;p&gt;Tener una test suite te puede hacer de malla protectora y ayudarte a detectar bugs que creas cuando estés programando una nueva funcionalidad o cuando estés haciendo un refactor. Además,  tus tests pueden ayudar a futuros desarrolladores a entender mas el código que has creado ya que un test es la mejor documentación que hay.&lt;/p&gt;

&lt;p&gt;¡Eso es todo por ahora! Espero que te haya gustado este post. Si te ha gustado, compártelo con tus amigos y compañeros de trabajo así todos podemos aprender un poco mas de testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quieres saber más
&lt;/h2&gt;

&lt;p&gt;Si te ha gustado este artículo y quieres saber sobre otros temas que te interesen puedes dejar un comentario o escribirme a cualquiera de mis redes sociales.&lt;/p&gt;

&lt;p&gt;🐦 &lt;strong&gt;&lt;a href="http://www.twitter.com/coding__pizza"&gt;Twitter&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📘 &lt;strong&gt;&lt;a href="http://www.facebook.com/codingpizza"&gt;Facebook&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📷 &lt;strong&gt;&lt;a href="http://www.instagram.com/codingpizza"&gt;Instagram&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>testing</category>
    </item>
    <item>
      <title>What is a unit test</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Tue, 21 Jan 2020 19:32:34 +0000</pubDate>
      <link>https://forem.com/codingpizza/what-is-a-unit-test-1e1m</link>
      <guid>https://forem.com/codingpizza/what-is-a-unit-test-1e1m</guid>
      <description>&lt;h1&gt;
  
  
  What is a unit test
&lt;/h1&gt;

&lt;p&gt;You probably seen in those job offers, "Experience with Tests and TDD." But if you're like me you probably have no idea about tests, you heard about them, and you know that the good developers are using it. But, what are they? how they work?&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Let's start with the test
&lt;/h2&gt;

&lt;p&gt;When a QA comes to me and asks me if I'm confident about what my code is supposed to do, I always answer no, and that's because I know I could mess it up. It's not because I don't trust my coding skills. It's because I'm human, and we made mistakes. That's why I started learning about testing because an excellent test suite can help you to catch the bugs that you're going to introduce.&lt;/p&gt;

&lt;p&gt;A test determines something; in our case, we want that our code goes as we planned. In my vague words, a test is a code that you write to verify that the "production" code you wrote is doing what is supposed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  👩‍💼👨‍💼The unit
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;An individual thing or person regarded as single and complete but which can also form an individual component of a larger or more complex whole.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Taken from &lt;a href="https://www.lexico.com/en/definition/unit"&gt;lexico&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our case, a unit can be a class or a function which can group to create an App. We can test our units to be sure that each unit does what it's supposed to do, and if we do that, we're doing unit testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  👩‍💼👨‍💼 Testing the unit
&lt;/h3&gt;

&lt;p&gt;Let's say we are building a shiny, never made before, unique app called calculator. In this app, we have a function called sum(), which realizes an addition of two numbers. In Kotlin, it will be.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun sum(int a,int b) : Int {
    return a+a;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we jump into making our UI because the UI is fantastic, and I love to make the UI, and when we run the app and start testing it, we are surprised because the sum isn't working. Why isn't this working? The parameters are a and b. Trust me, this thing happens.&lt;/p&gt;

&lt;p&gt;There's a problem if your build times take some time. You probably know that a full compilation time can break your productivity flow. I hope you're not like me who get distracted easily and forget what I was doing. Unit testing can help us to solve these two problems because the tests verify that the code is doing what it's supposed to do. Unit tests run faster than compiling the app and manually testing it, so let's create our first test.&lt;/p&gt;

&lt;p&gt;Almost every language has its unit testing frameworks. You can check your language unit testing framework &lt;a href="https://en.wikipedia.org/wiki/List_of_unit_testing_framework"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. In this case, I'm using Kotlin, so we're going to use JUnit.&lt;/p&gt;

&lt;p&gt;A unit test looks like this and, by default, lives in your test folder.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @Test
    fun calculator_sum_shouldReturnTheSumBetweenTwoParameters() {
        //Given
        val calculator = Calculator()
        //When
        val result = calculator.sum(2, 1)
        //Then
        assertEquals(3,result)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Analyzing the anatomy of these tests, we can observe the next things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;@Test&lt;/code&gt; annotation which indicates that is a Test.&lt;/li&gt;
&lt;li&gt;The name of the function which indicates [Unit_WhatWeAreTesting_ExpectedBehavior].&lt;/li&gt;
&lt;li&gt;The body of the test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test should follow the Arrange-Act-Assert or the Given-When-Then Pattern. I like the given, when, then pattern because it reminds me of the user stories. And when you can get easily distracted it helps you well! Let's talk about that pattern!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given: In this section, the objects which we're going to need are created.&lt;/li&gt;
&lt;li&gt;When: Here, we call the method to test.&lt;/li&gt;
&lt;li&gt;Then: Finally, in the last section, we do the assertions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NcUnGA21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bj8lz6o69ifd1a17ei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NcUnGA21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/e4bj8lz6o69ifd1a17ei.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm using Intellij Idea, so there's a play button close to that test, we click on it, and there's a message indicating that the test failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G3tCrZyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tvaux78n0q94dikrati2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G3tCrZyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tvaux78n0q94dikrati2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our test failed because our function is returning the sum between our first parameter 🤦‍♂. Now we can change our function to the following and it will pass!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun sum(int a,int b) : Int {
    return a+b;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AQsnczSJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8l37t5h0gair3xam8qje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AQsnczSJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8l37t5h0gair3xam8qje.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazing. I must admit now the green has become one of my favorite colors since it's the color that the tests show when it passes!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kotlin Note&lt;/strong&gt;: In Kotlin, we can use backticks to wrap the name of the test so it can be more readable!&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test&lt;br&gt;
    fun &lt;code&gt;calculator sum should Return The Sum Between Two Parameters&lt;/code&gt;() {&lt;br&gt;
        //Given&lt;br&gt;
        val calculator = Calculator()&lt;br&gt;
        //When&lt;br&gt;
        val result = calculator.sum(2, 1)&lt;br&gt;
        //Then&lt;br&gt;
        assertEquals(3,result)&lt;br&gt;
    }&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  🔺 The pyramid of testing&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;We already saw what a unit test is, but there are more types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit Test, as we mentioned before this test only the subject.&lt;/li&gt;
&lt;li&gt;Integration Test verifies that two or more units are working together as they should.&lt;/li&gt;
&lt;li&gt;End to End Test verifies that all the units are working together as they should. The end to end test in the case of Android includes UI testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we have three types of testing, we need to split them reasonably. All can't be End to End Test of Integration Tests. And fortunately, there's an image which explains very well how we should distribute our testing, and it's called the pyramid of testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp3Vn4IR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h6my1l2dgju7rhq8p8mp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp3Vn4IR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h6my1l2dgju7rhq8p8mp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pyramid of testing was created by Mike Cohn in his book, Succeeding with Agile. He states that the unit tests should be the base, then the Integration Tests, and finally the End to End Tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤓 More benefits of testing
&lt;/h2&gt;

&lt;p&gt;When you have a test suite, it works like a fallback network that can help you to avoid introducing new bugs when you are creating a new feature or refactoring the code. Also, your tests can help future developers who came after you to understand more what a feature is doing because the test is the best documentation.&lt;/p&gt;

&lt;p&gt;That's all for now! I hope you enjoyed this post. If you like it, don't forget to share it with your friends and coworkers so they can know more about testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get in touch
&lt;/h2&gt;

&lt;p&gt;Chat with me on:&lt;/p&gt;

&lt;p&gt;🐦 &lt;strong&gt;&lt;a href="http://www.twitter.com/coding__pizza"&gt;Twitter&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📘 &lt;strong&gt;&lt;a href="http://www.facebook.com/codingpizza"&gt;Facebook&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📷 &lt;strong&gt;&lt;a href="http://www.instagram.com/codingpizza"&gt;Instagram&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>kotlin</category>
      <category>testing</category>
    </item>
    <item>
      <title>Guardar en base de datos con Flutter</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 08 Jan 2020 20:48:13 +0000</pubDate>
      <link>https://forem.com/codingpizza/guardar-en-base-de-datos-con-flutter-2phl</link>
      <guid>https://forem.com/codingpizza/guardar-en-base-de-datos-con-flutter-2phl</guid>
      <description>&lt;h1&gt;
  
  
  Guardar en base de datos con Flutter
&lt;/h1&gt;

&lt;p&gt;Photo by Tim Evans on Unsplash.&lt;/p&gt;

&lt;p&gt;Almacenar texto en la base de datos es junto a las llamadas a red, una de las operaciones que como desarrolladores más tenemos que realizar. Algunas veces, necesitamos guardar la información de los servidores en nuestra app para que los usuarios puedan abrir la app y ver información previamente guardada antes de que se actualice con nuevo contenido, o podemos también tener que implementar un modo offline.&lt;/p&gt;

&lt;p&gt;En este artículo, vamos a hablar sobre cómo almacenar información en una app con Flutter. Nuestra app será una aplicación que almacenará unas Tareas por realizar (Todo's), las cuales podremos consultar luego. &lt;/p&gt;

&lt;p&gt;Una lista de las cosas que vamos a necesitar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Una clase de Tareas por realizar (De ahora en adelante las llamaremos Todo).&lt;/li&gt;
&lt;li&gt;Una Screen, la cual es un Widget que nos mostrará unos campos donde podremos crear nuestro Todo.&lt;/li&gt;
&lt;li&gt;Agregar las dependencias de los paquetes que utilizaremos. Un paquete es lo que en otros lenguajes puede conocerse como librería, nosotros utilizaremos &lt;strong&gt;sqflite&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Una clase DatabaseHelper la cual se encargará de gestionar la base de datos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338767.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338767.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338767.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Primero, vamos a crear nuestra clase Todo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Todo {
  final int id;
  final String content;
  final String title;
  static const String TABLENAME = "todos";

  Todo({this.id, this.content, this.title});

  Map&amp;lt;String, dynamic&amp;gt; toMap() {
    return {'id': id, 'content': content, 'title': title};
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Esta es la clase Todo la cual contiene un id, el contenido del Todo y el título. Además, agregamos una constante que incluye el nombre de la tabla de Todos, así como también una función toMap que utilizaremos más adelante. &lt;/p&gt;

&lt;p&gt;Con la clase Todo creada, vamos a agregar nuestra dependencia de la siguiente forma en el archivo pubspec.yml.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter
  sqflite:
  path:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ahora tenemos que crear nuestra clase &lt;strong&gt;DatabaseHelper,&lt;/strong&gt; la cual tiene la función de tratar con la base de datos. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DatabaseHelper {
  //Create a private constructor
  DatabaseHelper._();

  static const databaseName = 'todos_database.db';
  static final DatabaseHelper instance = DatabaseHelper._();
  static Database _database;

  Future&amp;lt;Database&amp;gt; get database async {
    if (_database == null) {
      return await initializeDatabase();
    }
    return _database;
  }

  initializeDatabase() async {
    return await openDatabase(join(await getDatabasesPath(), databaseName),
        version: 1, onCreate: (Database db, int version) async {
      await db.execute(
          "CREATE TABLE todos(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, title TEXT, content TEXT)");
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Tenemos varias cosas de las que hablar sobre esta clase. Para empezar, acceder a una base de datos es una operación asíncrona, lo que significa que debemos utilizar Futures para inicializar la propiedad &lt;strong&gt;database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En la función &lt;strong&gt;initializeDatabase&lt;/strong&gt; vamos a inicializar una base de datos siempre y cuando no tengamos una ya creada previamente, para inicializarla vamos a llamar la función &lt;strong&gt;initializeDatabase&lt;/strong&gt; y dentro de ella llamaremos a la función &lt;strong&gt;openDatabase&lt;/strong&gt; de la librería de sqflite.&lt;/p&gt;

&lt;p&gt;La función &lt;strong&gt;openDatabase&lt;/strong&gt; necesita los siguientes parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un String que sería el &lt;strong&gt;Path&lt;/strong&gt; de la base de datos. Para esto, debido a que tratamos con sistemas operativos diversos, hay que utilizar la función &lt;strong&gt;join()&lt;/strong&gt; que se encargará de unir los path que vamos a obtener con la función &lt;strong&gt;getDatabasesPath()&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Una función anónima que será ejecutada cuando la base de datos sea creada. En nuestro caso, una función anónima con una query creará una tabla dentro de la base de datos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La función &lt;strong&gt;insertTodo()&lt;/strong&gt; toma como parámetro un objeto &lt;strong&gt;Todo.&lt;/strong&gt; Obtiene la base de datos que habíamos creado previamente y utiliza la función de la librería sqflite &lt;strong&gt;execute()&lt;/strong&gt; para insertar los datos en nuestra base de datos. A esta función le vamos a pasar los siguientes parámetros.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El nombre de la tabla en la cual vamos a insertar la información. En nuestro caso tenemos el nombre declarado como una constante en nuestra clase de Todo.&lt;/li&gt;
&lt;li&gt;Un map que incluye la información que queremos insertar. Para esto hemos creado la función &lt;strong&gt;toMap&lt;/strong&gt; de nuestra clase Todo que convierte nuestro objeto Todo a un Map.&lt;/li&gt;
&lt;li&gt;Y una constante definida por la librería que especificará qué acción tomar cuando se encuentre un conflicto. Nosotros vamos a tomar la acción de reemplazar siempre que tenga un conflicto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finalmente, podemos crear nuestra Screen la cual nos servirá para crear nuestro Todo object. Dado que los campos serán editables necesitaremos utilizar un StatefulWidget con su respectivo State. Los widgets que vamos a utilizar son Textfields y FloatingActionButton para guardar el Todo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CreateTodoScreen extends StatefulWidget {

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() {
    return _CreateTodoState();
  }
}

class CreateTodoScreen extends StatefulWidget {

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() {
    return _CreateTodoState();
  }
}

class _CreateTodoState extends State&amp;lt;CreateTodoScreen&amp;gt; {
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  @override
  void dispose() {
    super.dispose();
    descriptionTextController.dispose();
    titleTextController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrieve Text Input'),
      ),
      body: Column(
        children: &amp;lt;Widget&amp;gt;[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Title"),
              maxLines: 1,
              controller: titleTextController,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Description"),
              maxLines: 10,
              controller: descriptionTextController,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.check),
          onPressed: () {
            DatabaseHelper.instance.insertTodo(Todo(
              title: titleTextController.text,
              content: descriptionTextController.text));
            Navigator.pop(context, "Your todo has been saved.");
          }),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Luego de crear nuestro State necesitamos utilizar un &lt;strong&gt;TextEditingController&lt;/strong&gt; para cada uno de nuestros TextFields, estos los declaramos al principio de nuestro Widget y hacemos un &lt;strong&gt;&lt;em&gt;override&lt;/em&gt;&lt;/strong&gt;  de la función dispose() para llamar a la respectiva función dispose de cada &lt;strong&gt;TextEditingController.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Al momento de crear nuestros &lt;strong&gt;TextFields&lt;/strong&gt;, le pasamos a cada TextField su respectivo controller. Finalmente, para llamar al &lt;strong&gt;DatabaseHelper&lt;/strong&gt; e indicarle que llame a la función &lt;strong&gt;insertTodo&lt;/strong&gt; debemos pasarle a la propiedad &lt;strong&gt;onPressed&lt;/strong&gt; del &lt;strong&gt;floatingActionButton&lt;/strong&gt; una función anónima con un &lt;strong&gt;Todo&lt;/strong&gt; creado usando el texto obtenido de los &lt;strong&gt;TextEditingController&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338787.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338787.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338787.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Actualizando nuestros Todo's
&lt;/h2&gt;

&lt;p&gt;Para actualizar nuestros Todo's necesitamos hacer ciertas modificaciones. Primero, vamos a agregar esta nueva función a nuestro &lt;strong&gt;DatabaseHelper&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;updateTodo(Todo todo) async {
    final db = await database;

    await db.update(Todo.TABLENAME, todo.toMap(),
        where: 'id = ?',
        whereArgs: [todo.id],
        conflictAlgorithm: ConflictAlgorithm.replace);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En esta función obtenemos el objeto database y luego llamamos a la función &lt;strong&gt;update()&lt;/strong&gt; de la librería y le pasamos los siguientes parámetros.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El nombre de la tabla que hemos declarado previamente en nuestro objeto &lt;strong&gt;Todo&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;El objeto &lt;strong&gt;Todo&lt;/strong&gt; convertido a un map usando la función &lt;strong&gt;toMap.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;La cláusula &lt;strong&gt;where&lt;/strong&gt; la cual aplicará cambios en cualquier fila que cumpla con esa condición&lt;/li&gt;
&lt;li&gt;El parámetro &lt;strong&gt;whereArgs&lt;/strong&gt; que sustituirá el signo de interrogación en nuestra cláusula where.&lt;/li&gt;
&lt;li&gt;Y finalmente, una constante que especifica el tipo de algoritmo a usar en caso de que haya un conflicto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora debemos actualizar nuestra UI. Primero, vamos a modificar nuestra &lt;strong&gt;DetailTodoScreen&lt;/strong&gt; para poder editar nuestro Todo. Necesitaremos agregar nuestro &lt;strong&gt;Todo&lt;/strong&gt; como un parámetro opcional en el constructor del &lt;strong&gt;DetailTodoScreen&lt;/strong&gt;, luego crear una property &lt;strong&gt;Todo&lt;/strong&gt; en nuestro Widget y debido a que es un &lt;strong&gt;StatefulWidget&lt;/strong&gt; debemos pasarle este &lt;strong&gt;Todo&lt;/strong&gt; al State.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DetailTodoScreen extends StatefulWidget {
    final Todo todo;

  const DetailTodoScreen({Key key, this.todo}) : super(key: key);

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() =&amp;gt; _CreateTodoState(todo);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En nuestro State necesitamos agregar también nuestro Todo al constructor, crear la property Todo y sobrescribir la función initState de nuestro Widget para que podamos asignar el Título y la descripción de nuestro &lt;strong&gt;Todo&lt;/strong&gt; a los respectivos &lt;strong&gt;TextField&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class _CreateTodoState extends State&amp;lt;DetailTodoScreen&amp;gt; {
  Todo todo;
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  _CreateTodoState(this.todo);

  @override
  void initState() {
    super.initState();
    if (todo != null) {
      descriptionTextController.text = todo.content;
      titleTextController.text = todo.title;
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finalmente, en la función anónima que le pasamos como parámetro onPressed vamos a llamar a otra función llamada &lt;strong&gt;saveTodo,&lt;/strong&gt; la cual se encargará de insertar un nuevo Todo en caso de que no tengamos ningún &lt;strong&gt;Todo&lt;/strong&gt; para editar o de modificar un &lt;strong&gt;Todo&lt;/strong&gt; existente que hayamos pasado como parámetro a nuestro &lt;strong&gt;State&lt;/strong&gt;. Al final debemos llamar también a la función setState.&lt;/p&gt;

&lt;p&gt;Así es como se verá nuestro State luego de esas modificaciones.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class _CreateTodoState extends State&amp;lt;DetailTodoScreen&amp;gt; {
  Todo todo;
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  _CreateTodoState(this.todo);

  @override
  void initState() {
    super.initState();
    if (todo != null) {
      descriptionTextController.text = todo.content;
      titleTextController.text = todo.title;
    }
  }

  @override
  void dispose() {
    super.dispose();
    descriptionTextController.dispose();
    titleTextController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrieve Text Input'),
      ),
      body: Column(
        children: &amp;lt;Widget&amp;gt;[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Title"),
              maxLines: 1,
              controller: titleTextController,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Description"),
              maxLines: 10,
              controller: descriptionTextController,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.check),
          onPressed: () async {
            _saveTodo(titleTextController.text, descriptionTextController.text);
            setState(() {});
          }),
    );
  }

  _saveTodo(String title, String content) async {
    if (todo == null) {
      DatabaseHelper.instance.insertTodo(Todo(
          title: titleTextController.text,
          content: descriptionTextController.text));
      Navigator.pop(context, "Your todo has been saved.");
    } else {
      await DatabaseHelper.instance
          .updateTodo(Todo(id: todo.id, title: title, content: content));
      Navigator.pop(context);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deleting a Todo
&lt;/h2&gt;

&lt;p&gt;Para borrar un Todo necesitamos comenzar por borrar una función de nuestra clase &lt;strong&gt;DatabaseHelper.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deleteTodo(int id) async {
    var db = await database;
    db.delete(Todo.TABLENAME, where: 'id = ?', whereArgs: [id]);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Esta función llama a la función &lt;strong&gt;delete&lt;/strong&gt; de la librería Sqflite a la cual le pasamos el nombre de la tabla la cláusula where y el id del Todo a eliminar.&lt;/p&gt;

&lt;p&gt;Luego, para agregar una función de borrado en nuestra lista de todos vamos a necesitar realizar los siguientes pasos. Primero, en nuestro &lt;strong&gt;ListTile&lt;/strong&gt; widget vamos a necesitar a utilizar un parámetro opcional llamado &lt;strong&gt;trailing,&lt;/strong&gt; en este parámetro vamos a pasarle un &lt;strong&gt;IconButton&lt;/strong&gt;, dentro de ese parámetro &lt;strong&gt;onPressed&lt;/strong&gt; vamos a pasarle una función anónima que llamará a la función del &lt;strong&gt;DatabaseHelper&lt;/strong&gt; encargada de borrar el &lt;strong&gt;Todo&lt;/strong&gt;.&lt;/p&gt;

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

class _ReadTodoScreenState extends State&amp;lt;ReadTodoScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Saved Todos'),
      ),
      body: FutureBuilder&amp;lt;List&amp;lt;Todo&amp;gt;&amp;gt;(
        future: DatabaseHelper.instance.retrieveTodos(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(snapshot.data[index].title),
                  leading: Text(snapshot.data[index].id.toString()),
                  subtitle: Text(snapshot.data[index].content),
                  onTap: () =&amp;gt; _navigateToDetail(context, snapshot.data[index]),
                  trailing: IconButton(
                      alignment: Alignment.center,
                      icon: Icon(Icons.delete),
                      onPressed: () async {
                        _deleteTodo(snapshot.data[index]);
                        setState(() {});
                      }),
                );
              },
            );
          } else if (snapshot.hasError) {
            return Text("Oops!");
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

_deleteTodo(Todo todo) {
  DatabaseHelper.instance.deleteTodo(todo.id);
}

_navigateToDetail(BuildContext context, Todo todo) async {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) =&amp;gt; DetailTodoScreen(todo: todo)),
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338793.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codingpizza.com%2Fwp-content%2Fuploads%2F2020%2F01%2FScreenshot_1578338793.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338793.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¡Y eso es todo! Ahora tenemos un app que puede almacenar un Todo, leerlo desde base de datos, actualizarlo y borrarlo.&lt;/p&gt;

&lt;p&gt;El código está disponible &lt;a href="https://github.com/codingpizza/todoapp" rel="noopener noreferrer"&gt;aquí&lt;/a&gt;. Si quieres leer más artículos como estos o tienes alguna duda, puedes encontrarme en las siguientes redes sociales.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instagram&lt;/strong&gt;: &lt;a href="http://www.instagram.com/codingpizza" rel="noopener noreferrer"&gt;www.instagram.com/codingpizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Twitter&lt;/strong&gt;: &lt;a href="http://www.twitter.com/coding__pizza" rel="noopener noreferrer"&gt;www.twitter.com/coding__pizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Facebook&lt;/strong&gt;: &lt;a href="http://www.facebook.com/codingpizza" rel="noopener noreferrer"&gt;www.facebook.com/codingpizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Site&lt;/strong&gt;: &lt;a href="http://www.codingpizza.com/" rel="noopener noreferrer"&gt;www.codingpizza.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Storing in database with Flutter</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 08 Jan 2020 20:26:18 +0000</pubDate>
      <link>https://forem.com/codingpizza/storing-in-database-with-flutter-f24</link>
      <guid>https://forem.com/codingpizza/storing-in-database-with-flutter-f24</guid>
      <description>&lt;p&gt;Storing text in the Database is one of the most current operations that we, as developers, are going to do. Sometimes we need to save the data from the server so the users can open the app and if there's data already stored we can show that first, or if we want to implement an have an offline mode.&lt;/p&gt;

&lt;p&gt;Today we're going to see how to store data in Flutter. Our app is going to be a Todo app, where we store these todos to watch them later.&lt;/p&gt;

&lt;p&gt;What we're going to need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Todo Class.&lt;/li&gt;
&lt;li&gt;A Screen, which let us create the Todo.&lt;/li&gt;
&lt;li&gt;Add the dependency for Sqflite.&lt;/li&gt;
&lt;li&gt;A DatabaseHelper which is a class that contains the logic of the Database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kaG_w4YK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338767.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kaG_w4YK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338767.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338767.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we're going to create our Todo class:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Todo {
  final int id;
  final String content;
  final String title;
  static const String TABLENAME = "todos";

  Todo({this.id, this.content, this.title});

  Map&amp;lt;String, dynamic&amp;gt; toMap() {
    return {'id': id, 'content': content, 'title': title};
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the Todo Class which has a content and a title as properties.&lt;/p&gt;

&lt;p&gt;Before creating our DatabaseHelper, we're going to add our dependencies to the pubspec.yml to do that we need to add the following lines below the flutter dependency.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter
  sqflite:
  path:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we're going to create our &lt;strong&gt;DatabaseHelper&lt;/strong&gt;, which is going to manage the Database for us.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DatabaseHelper {
  //Create a private constructor
  DatabaseHelper._();

  static const databaseName = 'todos_database.db';
  static final DatabaseHelper instance = DatabaseHelper._();
  static Database _database;

  Future&amp;lt;Database&amp;gt; get database async {
    if (_database == null) {
      return await initializeDatabase();
    }
    return _database;
  }

  initializeDatabase() async {
    return await openDatabase(join(await getDatabasesPath(), databaseName),
        version: 1, onCreate: (Database db, int version) async {
      await db.execute(
          "CREATE TABLE todos(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, title TEXT, content TEXT)");
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There's a lot of things going on there. Let's explain them. Accessing a database is an asynchronous operation, which means we must use Futures to initialize the &lt;strong&gt;database&lt;/strong&gt; property. In the function &lt;strong&gt;InitializeDatabase&lt;/strong&gt;, we're going to create a database using the &lt;strong&gt;openDatabase&lt;/strong&gt; function from the Sqlite library we added before, and we must pass the following parameters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A join function with the &lt;strong&gt;databasesPath()&lt;/strong&gt;, which is the path of the Database in their respective OS (Android, iOS) and the database name, which is a constant we already defined.&lt;/li&gt;
&lt;li&gt;An anonymous function that is going to be executed when the onCreate status is reached and inside of that function a query to be executed. In this example a query to create a Table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;insertTodo()&lt;/strong&gt; function is a function that takes a &lt;strong&gt;Todo&lt;/strong&gt; as a parameter and retrieves our previously created Database.&lt;/p&gt;

&lt;p&gt;Then we call the &lt;strong&gt;insert()&lt;/strong&gt; function, which takes three parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The name of the table in which it's going to insert that data, in our case is already defined in our Todo class.&lt;/li&gt;
&lt;li&gt;A map, which is the data we want to insert. For this, we have our &lt;strong&gt;toMap&lt;/strong&gt; function, which converts our &lt;strong&gt;Todo&lt;/strong&gt; object to a Map.&lt;/li&gt;
&lt;li&gt;A constant to decide which algorithm to use when the Database found the same Todo twice, in our case, we're going to use the replace one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we can create our Screen to fill our &lt;strong&gt;Todo&lt;/strong&gt; object. Since the fields are editable, the Widget must be a &lt;strong&gt;StatefulWidget&lt;/strong&gt;, so we create our &lt;strong&gt;StatefulWidget&lt;/strong&gt; with its respective State. The widgets that we're going to use are the &lt;strong&gt;TextFields&lt;/strong&gt; and a &lt;strong&gt;FloatingActionButton&lt;/strong&gt; to save the Todo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CreateTodoScreen extends StatefulWidget {

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() {
    return _CreateTodoState();
  }
}

class CreateTodoScreen extends StatefulWidget {

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() {
    return _CreateTodoState();
  }
}

class _CreateTodoState extends State&amp;lt;CreateTodoScreen&amp;gt; {
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  @override
  void dispose() {
    super.dispose();
    descriptionTextController.dispose();
    titleTextController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrieve Text Input'),
      ),
      body: Column(
        children: &amp;lt;Widget&amp;gt;[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Title"),
              maxLines: 1,
              controller: titleTextController,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Description"),
              maxLines: 10,
              controller: descriptionTextController,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.check),
          onPressed: () {
            DatabaseHelper().insertTodo(Todo(
                title: titleTextController.text,
                content: descriptionTextController.text));
            Navigator.pop(context, "Your todo has been saved.");
          }),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To retrieve the data from the &lt;strong&gt;TextField&lt;/strong&gt;, we're going to use &lt;strong&gt;TextEditingControllers&lt;/strong&gt;, which we initialize in the &lt;strong&gt;CreateTodoState&lt;/strong&gt; after that we override the function dispose of the &lt;strong&gt;CreateTodoState&lt;/strong&gt; and call the dispose function of each controller.&lt;/p&gt;

&lt;p&gt;Lately, when we create our &lt;strong&gt;TextField&lt;/strong&gt;, we pass their respective controller as a parameter. Finally, in the &lt;strong&gt;FloatingActionButton&lt;/strong&gt; onPressed parameter, we pass an anonymous function, which calls our &lt;strong&gt;DatabaseHelper&lt;/strong&gt; and inserts the Todo object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PNUQnbZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338787.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PNUQnbZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338787.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338787.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving the Todo's from the database.
&lt;/h2&gt;

&lt;p&gt;What we're going to do first is to add another Button to our &lt;strong&gt;HomeScreen.&lt;/strong&gt; For that, let's create a new Widget called &lt;strong&gt;ReadTodoButton.&lt;/strong&gt; This Widget returns a &lt;strong&gt;RaisedButtonWidget&lt;/strong&gt;, which has an onPressed function that uses the &lt;strong&gt;Navigator&lt;/strong&gt; to send us to the next screen, which is the &lt;strong&gt;ReadTodoScreen&lt;/strong&gt;, we're going to create this screen in the future.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;ReadTodoButton&lt;/strong&gt; Widget is going to look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ReadTodoButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        _navigateToReadTodoScreen(context);
      },
      child: Text("Read Todo"),
    );
  }

  _navigateToReadTodoScreen(BuildContext context) async {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) =&amp;gt; ReadTodoScreen()),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we're going to add it to the children's array of our HomeScreen Widget. And the result would be this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Create a todo'),
      ),
      body: Column(
        children: &amp;lt;Widget&amp;gt;[
          Center(child: CreateTodoButton()),
          Center(child: ReadTodoButton())
        ],
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we're going to add a new function in our &lt;strong&gt;DatabaseHelper&lt;/strong&gt; class, which is going to return the previously saved &lt;strong&gt;Todo's&lt;/strong&gt;. First, we're going to create a function that returns a list of Todo items wrapped in a Future object, and since it returns a Future, that function should include the async reserved keyword in their signature.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Future&amp;lt;List&amp;lt;Todo&amp;gt;&amp;gt; retrieveTodos() async {
    // Logic we will add later
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we will retrieve our Database object, and since it is an async operation, we're going to use the await keyword.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final Database db = await database;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step we're going to do is create a list of maps that have a key which is a String and a value that is going to be &lt;strong&gt;dynamic&lt;/strong&gt;, we obtain that value from a query function of the database. It will look as follows.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final List&amp;lt;Map&amp;lt;String, dynamic&amp;gt;&amp;gt; maps = await db.query(Todo.TABLENAME);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the database query function, we're going to pass the name of the table, which is defined in our Todo object.&lt;/p&gt;

&lt;p&gt;In the last step we need to convert that List of maps into a List of Todos. To do that, we need to create a list using the generate function which takes two parameters, the size of the List and an anonymous function.&lt;/p&gt;

&lt;p&gt;In the last step, we need to convert that list of maps into a List of Todos. For that we would need to create a list using the generate function which takes two parameters, the size of the list and an anonymous function.&lt;/p&gt;

&lt;p&gt;For the size of the list we can use the &lt;strong&gt;maps.length&lt;/strong&gt;, which gives us the length that we're going to need. For the anonymous function, we need to create a function that returns a Todo for each element of the list.&lt;/p&gt;

&lt;p&gt;The code will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return List.generate(maps.length, (i) {
      return Todo(
        id: maps[i]['id'],
        title: maps[i]['title'],
        content: maps[i]['content'],
      );
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We take the id, title, and content from the &lt;strong&gt;maps&lt;/strong&gt; variable, then we assign it to our new &lt;strong&gt;Todo&lt;/strong&gt; object.&lt;/p&gt;

&lt;p&gt;With that function, we finally have a function that returns our Todo's object. The only thing left is creating a new screen, which shows the Todo's.&lt;/p&gt;

&lt;p&gt;To create our ReadTodoScreen, we're going to create a Stateless Widget, which has a List as a Body . But since we're going to retrieve the data from a Future, we need to wrap our list in a FutureBuilder.&lt;/p&gt;

&lt;p&gt;A FutureBuilder is a widget that requires a generic which is declared inside angle brackets, and requires as a parameter a Future and the Builder.&lt;/p&gt;

&lt;p&gt;We're going to pass as a Future the function of our Database Helper, and as a builder, an anonymous function that needs the context and a snapshot, and the anonymous function return a Widget.&lt;/p&gt;

&lt;p&gt;Inside the anonymous function, we must check if the snapshot (The object which contains the Todo's) has data using the &lt;strong&gt;.hasData()&lt;/strong&gt; function. If it has, we're going to return a new ListView widget, otherwise, we're going to show a text with a message that says, "Oops!".&lt;/p&gt;

&lt;p&gt;We must also return a &lt;strong&gt;CircularProgressIndicator&lt;/strong&gt; to show while the operation is ongoing.&lt;/p&gt;

&lt;p&gt;The code of the screen is the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ReadTodoScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Saved Todos'),
      ),
      body: FutureBuilder&amp;lt;List&amp;lt;Todo&amp;gt;&amp;gt;(
        future: DatabaseHelper().retrieveTodos(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(snapshot.data[index].title),
                  subtitle: Text(snapshot.data[index].content),
                );
              },
            );
          } else if (snapshot.hasError) {
            return Text("Oops!");
          }
          return CircularProgressIndicator();
        },
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;strong&gt;ListView.Builder&lt;/strong&gt; function requires the size of the list that is going to be displayed and a Widget that is each tile of the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the Todo's
&lt;/h2&gt;

&lt;p&gt;To update our Todo's, we need to make certain modifications. First, we're going to add this new function to the DatabaseHelper.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;updateTodo(Todo todo) async {
    final db = await database;

    await db.update(Todo.TABLENAME, todo.toMap(),
        where: 'id = ?',
        whereArgs: [todo.id],
        conflictAlgorithm: ConflictAlgorithm.replace);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this function, we obtain the Database, then we call the function &lt;strong&gt;update()&lt;/strong&gt; from the Database, and we pass the next parameters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;tablename&lt;/strong&gt; we previously defined in our Todo object.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Todo&lt;/strong&gt; object converted into a map using the toMap function.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;where&lt;/strong&gt; parameter. Which is the clause to apply the changes. In our case, we want to use the id.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;whereArgs&lt;/strong&gt; parameter which is going to replace the "?" sign in the where clause.&lt;/li&gt;
&lt;li&gt;And finally, a Constant that specifies the algorithm to use in case there is a conflict.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this time, we need to update our UI. First, we're going to modify our &lt;strong&gt;DetailTodoScreen&lt;/strong&gt; to allow us to edit our Todo. We need to add a &lt;strong&gt;Todo&lt;/strong&gt; as an optional parameter in our &lt;strong&gt;DetailTodoScreen&lt;/strong&gt; constructor, then create a final &lt;strong&gt;Todo&lt;/strong&gt; property in our Widget, and since it is a &lt;strong&gt;StatefulWidget&lt;/strong&gt;, pass it to the State.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DetailTodoScreen extends StatefulWidget {
    final Todo todo;

  const DetailTodoScreen({Key key, this.todo}) : super(key: key);

  @override
  State&amp;lt;StatefulWidget&amp;gt; createState() =&amp;gt; _CreateTodoState(todo);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In our State we need to add the Todo as a parameter in the constructor, create the Todo property and override the initState in which we're going to set the title and the description if the Todo exists.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class _CreateTodoState extends State&amp;lt;DetailTodoScreen&amp;gt; {
  Todo todo;
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  _CreateTodoState(this.todo);

  @override
  void initState() {
    super.initState();
    if (todo != null) {
      descriptionTextController.text = todo.content;
      titleTextController.text = todo.title;
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, in the onPressed anonymous function, we need to call a new function, which is saveTodo, that is going to call the DatabaseHelper updateTodo function if we passed a previously created Todo. Otherwise, it will insert a new Todo in our Database. Finally, in the same onPressed anonymous function, we're going to call the setState function.&lt;/p&gt;

&lt;p&gt;This is how our State is going to look.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class _CreateTodoState extends State&amp;lt;DetailTodoScreen&amp;gt; {
  Todo todo;
  final descriptionTextController = TextEditingController();
  final titleTextController = TextEditingController();

  _CreateTodoState(this.todo);

  @override
  void initState() {
    super.initState();
    if (todo != null) {
      descriptionTextController.text = todo.content;
      titleTextController.text = todo.title;
    }
  }

  @override
  void dispose() {
    super.dispose();
    descriptionTextController.dispose();
    titleTextController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrieve Text Input'),
      ),
      body: Column(
        children: &amp;lt;Widget&amp;gt;[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Title"),
              maxLines: 1,
              controller: titleTextController,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(), labelText: "Description"),
              maxLines: 10,
              controller: descriptionTextController,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.check),
          onPressed: () async {
            _saveTodo(titleTextController.text, descriptionTextController.text);
            setState(() {});
          }),
    );
  }

  _saveTodo(String title, String content) async {
    if (todo == null) {
      DatabaseHelper.instance.insertTodo(Todo(
          title: titleTextController.text,
          content: descriptionTextController.text));
      Navigator.pop(context, "Your todo has been saved.");
    } else {
      await DatabaseHelper.instance
          .updateTodo(Todo(id: todo.id, title: title, content: content));
      Navigator.pop(context);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deleting a Todo
&lt;/h2&gt;

&lt;p&gt;To delete a Todo, we need to add the delete function to our DatabaseHelper.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deleteTodo(int id) async {
    var db = await database;
    db.delete(Todo.TABLENAME, where: 'id = ?', whereArgs: [id]);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This function calls the &lt;strong&gt;delete&lt;/strong&gt; function from the Sqflite library in which we pass the table name, the where clause, and the id of the Todo.&lt;/p&gt;

&lt;p&gt;Then in our UI, we're going to add a delete button in our &lt;strong&gt;Todo&lt;/strong&gt; List. In our &lt;strong&gt;ListTile&lt;/strong&gt; Widget, we're going to pass as a trailing parameter an &lt;strong&gt;IconButton&lt;/strong&gt; Widget. Finally, in the &lt;strong&gt;onPressed&lt;/strong&gt; parameter, we're going to add an anonymous function that calls the deleteTodo from the &lt;strong&gt;DatabaseHelper&lt;/strong&gt; class.&lt;/p&gt;

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

class _ReadTodoScreenState extends State&amp;lt;ReadTodoScreen&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Saved Todos'),
      ),
      body: FutureBuilder&amp;lt;List&amp;lt;Todo&amp;gt;&amp;gt;(
        future: DatabaseHelper.instance.retrieveTodos(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(snapshot.data[index].title),
                  leading: Text(snapshot.data[index].id.toString()),
                  subtitle: Text(snapshot.data[index].content),
                  onTap: () =&amp;gt; _navigateToDetail(context, snapshot.data[index]),
                  trailing: IconButton(
                      alignment: Alignment.center,
                      icon: Icon(Icons.delete),
                      onPressed: () async {
                        _deleteTodo(snapshot.data[index]);
                        setState(() {});
                      }),
                );
              },
            );
          } else if (snapshot.hasError) {
            return Text("Oops!");
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

_deleteTodo(Todo todo) {
  DatabaseHelper.instance.deleteTodo(todo.id);
}

_navigateToDetail(BuildContext context, Todo todo) async {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) =&amp;gt; DetailTodoScreen(todo: todo)),
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--plwlC0qD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338793.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--plwlC0qD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338793.png" alt="https://www.codingpizza.com/wp-content/uploads/2020/01/Screenshot_1578338793.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! We now have an app that can store a Todo, read it from the database, update it, and delete it.&lt;/p&gt;

&lt;p&gt;The code is available &lt;strong&gt;&lt;a href="https://github.com/codingpizza/todoapp"&gt;here&lt;/a&gt;&lt;/strong&gt;. Thanks for reading! If you don't want to miss any of this post, don't forget to follow me!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instagram&lt;/strong&gt;: &lt;a href="http://www.instagram.com/codingpizza"&gt;www.instagram.com/codingpizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Twitter&lt;/strong&gt;: &lt;a href="http://www.twitter.com/coding__pizza"&gt;www.twitter.com/coding__pizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Facebook&lt;/strong&gt;: &lt;a href="http://www.facebook.com/codingpizza"&gt;www.facebook.com/codingpizza&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Site&lt;/strong&gt;: &lt;a href="http://www.codingpizza.com/"&gt;www.codingpizza.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>The Ectasy of the gratitude
</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Tue, 10 Dec 2019 19:43:19 +0000</pubDate>
      <link>https://forem.com/gvetri/the-ectasy-of-the-gratitude-3ldj</link>
      <guid>https://forem.com/gvetri/the-ectasy-of-the-gratitude-3ldj</guid>
      <description>&lt;p&gt;Photo by Hello I'm Nik 🇬🇧 on Unsplash&lt;/p&gt;

&lt;p&gt;I’m an Android developer from Venezuela who works and lives in Madrid. I’ve been in this city for two years, I love Madrid and Spanish food. I always wanted to start a blog where I could share my experiences and learnings as a developer. I started it, and I wrote a few blog posts about Android and other tech things. I even started a series about Dart, a programming language.&lt;/p&gt;

&lt;h3&gt;
  
  
  But this is not a post about tech
&lt;/h3&gt;

&lt;p&gt;It’s about gratitude.&lt;/p&gt;

&lt;p&gt;In the last months, I’ve been coming home after work and relaxed a bit playing some games. After 45–60 minutes, I started writing or learning something from the internet, I never stop learning. I’m a big fan of startups, programming, community management, and lately marketing so I’m always learning something new about one of these topics.&lt;/p&gt;

&lt;p&gt;After writing or learning about some of these, I go to the gym because I have some back pain if I do not continuously exercise, and it also helps me to clear my mind. When I come back from the gym, I take a shower, cook dinner, and chat with my partner about how was our day.&lt;/p&gt;

&lt;p&gt;A few weeks ago, I visited my grandma in Sicily and had a great time. Being so many days without wifi consumed all my data plan, just checking twitter to see what was happening in the Android Dev Summit, a big event in the Android community where a lot of awesome developers things are showed. The FOMO was real.&lt;/p&gt;

&lt;p&gt;After I came back from Sicily, I got bloated about the many things I wanted to learn, and that collapsed me. I just got blocked mentally, and I could barely write three words about anything or sit in front of the computer to do some learning. I thought it was because of the trip, so I took some rest that week. That didn’t work.&lt;/p&gt;

&lt;p&gt;It started to get worse at the point I could not even go to the gym to distract myself. The anxiety caused me to do anything, and doing anything caused me more anxiety. I was in a loop of anxiety.&lt;/p&gt;

&lt;p&gt;I always read Twitter to keep myself informed about the latest news in the Android Community. But thanks to the feature of seeing what people like, fights appeared in my feed. If you have a Twitter account, you can see how much lack of empathy it’s on the platform. The sum of these events affected me indirectly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The gratitude
&lt;/h3&gt;

&lt;p&gt;I determined that I could not be feeling that way too much time, so I decided to start doing something, and I slowly started to learn and write again. Maybe there were just 15 minutes or less. But eventually, I got a result, I created another piece of content.&lt;/p&gt;

&lt;p&gt;After publishing it, a person that consume my content send me a private message through Instagram and told me that he really liked my content and has been helpful to him. He even asked me how can I create content when he was always out of time. He made me remind two things, that I created a blog to provide value to at least one person, and the other thing is If you are sharing your knowledge even a little at a time, you are doing more than most people. This message reminded me of how much I like to learn and how much I like to share what I learn. It made me think deeply about how gratitude it’s the ecstasy of sharing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be grateful
&lt;/h3&gt;

&lt;p&gt;I don’t know about you, but probably you have some content creators which content you really like. Maybe it’s a podcast, a publisher, or a YouTuber; whatever the platform is, take a minute or two to send them a tweet, leave a comment or send them a private message about how much you like their content. Maybe they’re passing through a hard time, and that message would make their day.&lt;/p&gt;

&lt;p&gt;Have you ever feel this way? What is holding you for sharing your knowledge? Leave it in the comments, and let’s talk about it 🙌.&lt;/p&gt;

</description>
      <category>self</category>
      <category>mindset</category>
    </item>
    <item>
      <title>Classes en Dart</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 16 Oct 2019 17:12:52 +0000</pubDate>
      <link>https://forem.com/codingpizza/classes-en-dart-1ole</link>
      <guid>https://forem.com/codingpizza/classes-en-dart-1ole</guid>
      <description>&lt;p&gt;Hola! Hemos estado aprendiendo sobre Dart por algunas semanas, si has seguido esta serie espero que hayas aprendido un montón. En este post vamos a hablar sobre cómo funcionan las Clases en Dart, las cuales son uno de los fundamentos básicos de la programación.&lt;/p&gt;

&lt;h2&gt;
  
  
  📘 Qué es una Clase
&lt;/h2&gt;

&lt;p&gt;Una clase es un plano de un objeto. Dentro de la clase podemos encontrar las propiedades del objeto sus constructores y sus funciones. Ya hemos hablado de funciones en Dart así que no tocaremos ese tema en esta oportunidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Properties
&lt;/h3&gt;

&lt;p&gt;Las propiedades de una clase son variables declaradas al interno de una clase. Por ejemplo, si tenemos una clase Car (Carro), el color del carro puede ser una variable String con el valor Blue (Azul).&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructors
&lt;/h3&gt;

&lt;p&gt;Los constructores nos ayudan a inicializar los valores de nuestros objetos. Cuando creamos una clase y pasamos como variable algún parámetro, estamos usando un constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Cómo crear una clase en Dart
&lt;/h2&gt;

&lt;p&gt;Para crear una Clase en Dart, necesitamos usar la palabra reservada Class y luego indicar el nombre de la clase. Por ejemplo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {

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

&lt;/div&gt;

&lt;p&gt;Con esto podemos crear cualquier Dog(Perro) que queramos. Pero hay más, nuestro perro necesita un nombre, así que vamos a crear una variable que le asigne ese nombre.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;¡Genial! Ahora cada vez que creemos un nuevo Dog, va a tener Rocky como su nombre. Ahora necesitamos agregar la habilidad de ladrar a nuestro perro. Para eso, necesitamos crear una función. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";

  void bark(){
    print("Woof Woof! 🐶");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ya hemos creado nuestro plano para un perro llamado Rocky el cual puede ladrar. Todo lo que necesitamos hacer es crear un objeto a partir de este plano, para ello hay que utilizar el constructor.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var MyDoggo = Dog();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En el ejemplo anterior se muestra cómo podemos crear un objeto Dog utilizando un constructor por defecto. Pero, ¿qué pasaría si necesitaramos crear otro perro con otro nombre? No todos los perros se llaman Rocky.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐶 Creando perros únicos con constructores
&lt;/h2&gt;

&lt;p&gt;Para asignar el nombre de nuestros perros necesitamos crear un constructor dentro de una clase, este constructor nos ayudará a inicializar nuestros objetos perros con su respectivo nombre.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";

  Dog(this.name)

  void bark(){
    print("Woof Woof! 🐶");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ahora podemos crear otros perros de la siguiente forma.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var doggo = Dog("Sparky");
doggo.bark();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Existen otros tipos de constructores. Vamos a hablar de ellos en el siguiente post de CodingSlices Extended. Recuerda darle al follow para que no te pierdas los ultimos post.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐕 Para terminar, dejo aquí este perrito.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/2vmgb8ZGaeBsuSeo5I/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/2vmgb8ZGaeBsuSeo5I/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Eso es todo
&lt;/h2&gt;

&lt;p&gt;Espero que te haya gustado. Estoy creando nuevas CodingSlices sobre Flutter en Instagram, puedes seguirme en &lt;a href="https://www.instagram.com/codingpizza/"&gt;**@codingpizza&lt;/a&gt;** y en Twitter como &lt;a href="https://twitter.com/coding__pizza"&gt;&lt;strong&gt;@coding__pizza&lt;/strong&gt;&lt;/a&gt; para aprender sobre &lt;strong&gt;Flutter&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ahora es tu turno
&lt;/h2&gt;

&lt;p&gt;Puedes probar estos conceptos en Entornos de desarrollo (IDE) como &lt;a href="https://www.jetbrains.com/idea/download/"&gt;Intellij Idea Communit&lt;/a&gt;y, que es gratis e instalar el plugin de Dart, si te gusta Visual Studio Code tambien puedes probar estos conceptos en él y por último, si prefieres algo online puedes utilizar &lt;a href="https://dartpad.dartlang.org/"&gt;**Dartpad&lt;/a&gt;.**&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Quieres saber más sobre Dart?
&lt;/h2&gt;

&lt;p&gt;Si te ha gustado este post y estás interesado en aprender Dart, actualmente estoy escribiendo más artículos como este en un ebook, el cual es un curso básico de Dart que te ayudará a tener un buen conocimiento que luego podrás utilizar para empezar con Flutter ;). Puedes darte de alta &lt;a href="https://www.codingpizza.com/curso-dart-gratis/"&gt;**en este link&lt;/a&gt;** ya que el ebook será &lt;strong&gt;totalmente gratis.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>dart</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Classes in Dart</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 16 Oct 2019 17:07:51 +0000</pubDate>
      <link>https://forem.com/codingpizza/classes-in-dart-5ejf</link>
      <guid>https://forem.com/codingpizza/classes-in-dart-5ejf</guid>
      <description>&lt;p&gt;Hi! We've been learning about Dart for some weeks, if you've been following this series, you know we learned a lot of topics. In this post we're going to talk about Classes in Dart, the Classes are one of the basics of programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  📘 What is a Class
&lt;/h2&gt;

&lt;p&gt;A class is the object blueprint. Inside the class, we can find their properties, constructors, and functions. We already talked about functions in Dart, so we're going to skip that part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Properties
&lt;/h3&gt;

&lt;p&gt;The class properties are variables declared inside the class. For example, if we have a class named Car, the car color can be a string variable with the value "Blue."&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructors
&lt;/h3&gt;

&lt;p&gt;The constructors help us to initialize and set the values of our object. When we create a class and pass some variable as a parameter, we're using a constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 How to create a Class in Dart
&lt;/h2&gt;

&lt;p&gt;To create a Class in Dart, we need to use the reserved keyword class and then the name of the Class. For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {

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

&lt;/div&gt;

&lt;p&gt;With this, we can create any Dog we want. But there's more our Dog needs a name, so let's create a variable that assigns that name.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's great! Now every time we create a new Dog, it's going to have Rocky as the name. Now we need to add our dog's ability to bark. For that, we need to create a function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";

  void bark(){
    print("Woof Woof! 🐶");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We already have a blueprint for a Dog named Rocky who can bark. All we need to do is create an object from this blueprint is use the constructor.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var MyDoggo = Dog();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The previous example shows us how we can create a Dog object using a default constructor. But what if we want to create another dog with another name? Not all dogs are named Rocky.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐶 Creating uniques dogs with constructors
&lt;/h2&gt;

&lt;p&gt;To assign the name of our Dogs, we need to create a Constructor inside the class, which can help us to initialize our Dog objects with their name.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Dog {
  String name = "Rocky";

  Dog(this.name)

  void bark(){
    print("Woof Woof! 🐶");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we can create our Dogs using the following code.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var doggo = Dog("Sparky");
doggo.bark();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There are more Constructors. We're going to talk about those in the next CodingSlices Extended. Remember to follow me, so you don't miss it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐕 Finally, here is a spooky dog .
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/2vmgb8ZGaeBsuSeo5I/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/2vmgb8ZGaeBsuSeo5I/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;I hope you liked it. Do you want to learn more? I'm also creating new CodingSlices about Flutter on Instagram, feel free to follow me in &lt;strong&gt;@codingpizza&lt;/strong&gt; for more content.&lt;/p&gt;

&lt;p&gt;I'm also writing an eBook, which is a basic course of Dart. It's about all you need to know to get started with Flutter. &lt;strong&gt;&lt;a href="https://www.codingpizza.com/en/free-dart-course/"&gt;It's free, and you can sign-up here.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Now is your turn
&lt;/h2&gt;

&lt;p&gt;You can try these concepts in IDE like Intellij idea community, which is free. All you need is to install the Dart plugin. Visual Studio Code or in some online editors like &lt;a href="https://dartpad.dartlang.org/"&gt;&lt;strong&gt;Dartpad&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dart</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Funciones increibles que debes conocer al trabajar con Dart</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 09 Oct 2019 18:25:01 +0000</pubDate>
      <link>https://forem.com/codingpizza/funciones-increibles-que-debes-conocer-al-trabajar-con-dart-5cc2</link>
      <guid>https://forem.com/codingpizza/funciones-increibles-que-debes-conocer-al-trabajar-con-dart-5cc2</guid>
      <description>&lt;h1&gt;
  
  
  Funciones increibles que debes conocer al trabajar con Dart
&lt;/h1&gt;

&lt;p&gt;En los post anteriores sobre Dart, hablamos sobre las Collections. Hablamos sobre Lists,Maps y sets. Y en esta oportunidad vamos a hablar sobre funciones asombrosas y que nos pueden ayudar en muchos casos.&lt;/p&gt;

&lt;p&gt;Nota:En este post usamos varios elementos que probablemente quieras repasar, como las funciones anónimas. Si es tu primera vez leyendo esta serie de artículos puedes aquí debajo te dejo el link para que leas sobre funciones en &lt;strong&gt;Dart&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/codingpizza/funciones-en-dart-19on"&gt;&lt;strong&gt;Funciones en Dart&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Map&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;map&lt;/strong&gt; function exists in many programming languages, and Dart is not an exception. This function creates a new list after transform every element of the previous list. This function takes as a parameter an anonymous function. Let's see an example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.of({1,2,3,4});
var mappedList = list.map( (number) =&amp;gt; number *2);
print(mappedList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Esta función existe en muchos lenguajes de programación y dart no es la excepción. Esta función crea una nueva lista después de transformar cada elemento de la lista anterior. Esta función recibe como parámetro una función anónima. Veamos un ejemplo.&lt;/p&gt;

&lt;p&gt;En este ejemplo, hemos creado una función anónima que tiene un número como parámetro y hemos multiplicado este número por dos. El resultado de la función es &lt;code&gt;(2,4,6,8).&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sort
&lt;/h2&gt;

&lt;p&gt;Muchas veces necesitamos recibir una lista desde el servidor y mostrarla al usuario. Pero ¿qué ocurre si necesitamos aplicar algunos filtros y ordenarla de forma ascendente? Esta función está aquí para ayudarnos con eso, veamos un ejemplo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
randomNumbers.sort();
print(randomNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;El resultado es el siguiente.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 6, 14, 22, 23, 45, 51]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Generate
&lt;/h2&gt;

&lt;p&gt;La función generate es genial cuando necesitas crear una lista de números para hacer una prueba rápida. Toma como parámetro un número el cual indica el tamaño de la lista y una función anónima.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var generatedList =
      List.generate(10, (number) =&amp;gt; number * Random().nextInt(50));
  print(generatedList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Dentro de la función anónima obtenemos un número y lo multiplicamos por un número aleatorio entre 0 y 50.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take
&lt;/h2&gt;

&lt;p&gt;Ya solo con su nombre en inglés te explica que hace esta función simplemente toma los primeros elementos de la lista. Puede ser útil cuando tengas una lista de competidores y quieras solo obtener el top tres de todos los competidores.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.from([1,2,3,4,5,6]);
var topThreeList = list.take(3);
print(topThreeList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;El resultado es: &lt;code&gt;1,2,3&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Skip
&lt;/h2&gt;

&lt;p&gt;Esta función es el opuesto de la función Take, está ignora la cantidad de elementos que se le indique. En caso de que se le indiquen 3 elementos obviara los primeros tres elementos de la lista.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.from([1,2,3,4,5,6]);
var skipList = list.skip(3);
print(skipList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;El resultado es: &lt;code&gt;4,5,6&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where
&lt;/h2&gt;

&lt;p&gt;Esta función es una de mis favoritas ya que nos ayuda a crear una lista con los elementos que cumplan con el predicado que se le pasa como parámetro. Esto quiere decir que solo los elementos que cumplan con la condición dada se agregaran a la lista.&lt;/p&gt;

&lt;p&gt;Digamos que tenemos una lista aleatoria de números en caso de que queramos una lista con solo numeros pares bastará realizar esa comprobación en la función anónima. Veamos el siguiente ejemplo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
var evenNumbers = randomNumbers.where((number =&amp;gt; number.isEven));
print(evenNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;El resultado del ejemplo anterior es el siguiente: &lt;code&gt;14,6,22&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un buen tip
&lt;/h2&gt;

&lt;p&gt;Estas funciones pueden combinarse para lograr una mejor solución. Puedes combinar la función where con la función sort para obtener los números pares ordenados de forma ascendente por ejemplo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
var evenNumbers = randomNumbers.where((number) =&amp;gt; number.isEven);
evenNumbers = evenNumbers.toList()..sort();
print(evenNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En este ejemplo tomamos solamente los números pares de la lista randomNumberList, luego convertimos esos números a una Lista y finalmente usamos el operador de cascada &lt;code&gt;..&lt;/code&gt; para ordenar la lista de forma ascendente.&lt;/p&gt;

&lt;p&gt;El resultado final es:  &lt;code&gt;[6, 14, 22]&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Eso es todo
&lt;/h2&gt;

&lt;p&gt;Espero que te haya gustado. Estoy creando nuevas CodingSlices sobre Flutter en Instagram, puedes seguirme en &lt;a href="https://www.instagram.com/codingpizza/"&gt;**@codingpizza&lt;/a&gt;** y en Twitter como &lt;a href="https://twitter.com/coding__pizza"&gt;&lt;strong&gt;@coding__pizza&lt;/strong&gt;&lt;/a&gt; para aprender sobre &lt;strong&gt;Flutter&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ahora es tu turno
&lt;/h2&gt;

&lt;p&gt;Puedes probar estos conceptos en Entornos de desarrollo (IDE) como &lt;a href="https://www.jetbrains.com/idea/download/"&gt;Intellij Idea Communit&lt;/a&gt;y, que es gratis e instalar el plugin de Dart, si te gusta Visual Studio Code tambien puedes probar estos conceptos en él y por último, si prefieres algo online puedes utilizar &lt;a href="https://dartpad.dartlang.org/"&gt;&lt;strong&gt;Dartpad&lt;/strong&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Quieres saber más sobre Dart?
&lt;/h2&gt;

&lt;p&gt;Si te ha gustado este post y estás interesado en aprender Dart, actualmente estoy escribiendo más artículos como este en un ebook, el cual es un curso básico de Dart que te ayudará a tener un buen conocimiento que luego podrás utilizar para empezar con Flutter ;). Puedes darte de alta &lt;a href="https://www.codingpizza.com/curso-dart-gratis/"&gt;**en este link&lt;/a&gt;** ya que el ebook será &lt;strong&gt;totalmente gratis.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Post anterior
&lt;/h2&gt;

&lt;p&gt;Si estás interesado en más post como este puedes revisar mis otros artículos sobre Dart.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/codingpizza/variables-en-dart-3963"&gt;Variables&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/codingpizza/funciones-en-dart-19on"&gt;Funciones&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/codingpizza/parametros-en-dart-1f11"&gt;Parámetros&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/codingpizza/control-flow-en-dart-2651"&gt;Flujo de Control&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/gvetri/collections-en-dart-2pbh"&gt;Collections&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dart</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Powerful list functions in Dart that you should know</title>
      <dc:creator>Giuseppe Vetri</dc:creator>
      <pubDate>Wed, 09 Oct 2019 18:03:09 +0000</pubDate>
      <link>https://forem.com/codingpizza/powerful-list-functions-in-dart-that-you-should-know-4h4o</link>
      <guid>https://forem.com/codingpizza/powerful-list-functions-in-dart-that-you-should-know-4h4o</guid>
      <description>&lt;p&gt;In the previous post about Dart, we talked about &lt;strong&gt;Collections&lt;/strong&gt; in Dart. We spoke about List, Maps, and sets. And today, we're going to talk about some functions that are awesome and can help you in many cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In this post we use in various cases the anonymous function, if you are not familiarized with it, you can check my other post about &lt;strong&gt;functions&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Map&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;map&lt;/strong&gt; function exists in many programming languages, and Dart is not an exception. This function creates a new list after transform every element of the previous list. This function takes as a parameter an anonymous function. Let's see an example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.of({1,2,3,4});
var mappedList = list.map( (number) =&amp;gt; number *2);
print(mappedList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this example, we create an anonymous function that has a number as a parameter, and we multiply that number per two. The result of this function is: &lt;code&gt;(2,4,6,8)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sort
&lt;/h2&gt;

&lt;p&gt;Sometimes you receive a list from the server, and you need to show it to the user. But what if you need to apply some filter and sort it in an ascending way? Well, this function can help you.&lt;br&gt;
Let's see an example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
randomNumbers.sort();
print(randomNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the result.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 6, 14, 22, 23, 45, 51]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Generate
&lt;/h2&gt;

&lt;p&gt;This function is great when you need to create a list of numbers for a test. It takes as first parameter a number, which indicates the size of the list and an anonymous function which tells the &lt;strong&gt;generate()&lt;/strong&gt; function how to create the numbers inside the list.&lt;/p&gt;

&lt;p&gt;Here's an example.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var generatedList =
      List.generate(10, (number) =&amp;gt; number * Random().nextInt(50));
  print(generatedList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the example we can see how we can generate a list of ten elements and multiply it by a random number from 0 to 50.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;take&lt;/strong&gt; function literally takes the first elements from the list. This can be useful when you have a list of winners and want to take the top 3. Here's how you can use it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.from([1,2,3,4,5,6]);
var topThreeList = list.take(3);
print(topThreeList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result of this example is: &lt;code&gt;1,2,3&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Skip
&lt;/h2&gt;

&lt;p&gt;The skip function is the opposite of the take function. This function ignores the first elements and creates a list of the remaining ones. This example shows how you can use it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = List.from([1,2,3,4,5,6]);
var skipList = list.skip(3);
print(skipList);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result is: &lt;code&gt;4,5,6&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where
&lt;/h2&gt;

&lt;p&gt;This function is one of my favorites. It helps us to create a list of elements that satisfy a predicate. That means that your element list is going to have only elements that meet your requirements. Let's say that you need to create a list of only even numbers.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
var evenNumbers = randomNumbers.where((number =&amp;gt; number.isEven));
print(evenNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result of this example is &lt;code&gt;14,6,22&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  An awesome tip
&lt;/h2&gt;

&lt;p&gt;These function can be combined to achieve a greater solution. You can combine a &lt;strong&gt;where&lt;/strong&gt; function with a &lt;strong&gt;sort&lt;/strong&gt; function to get the even numbers sorted in ascending way.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var randomNumbers = List.of({14, 51, 23, 45, 6, 3, 22, 1});
var evenNumbers = randomNumbers.where((number) =&amp;gt; number.isEven);
evenNumbers = evenNumbers.toList()..sort();
print(evenNumbers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this example we take only the even numbers from the randomNumbersList, then we convert these numbers to a List finally we use the cascade operator &lt;code&gt;..&lt;/code&gt; to &lt;strong&gt;sort()&lt;/strong&gt; the list in an ascending way.&lt;/p&gt;

&lt;p&gt;The final result is: &lt;code&gt;[6, 14, 22]&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;I hope you liked it. Do you want to learn more? I'm also creating new CodingSlices about Flutter on Instagram, feel free to follow me in &lt;strong&gt;@codingpizza&lt;/strong&gt; for more content.&lt;/p&gt;

&lt;p&gt;I'm also writing an eBook, which is a basic course of Dart. It's about all you need to know to get started with Flutter. &lt;strong&gt;&lt;a href="https://www.codingpizza.com/en/free-dart-course/"&gt;It's free, and you can sign-up here.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Now is your turn
&lt;/h2&gt;

&lt;p&gt;You can try these concepts in IDE like Intellij idea community, which is free. All you need is to install the Dart plugin. Visual Studio Code or in some online editors like &lt;a href="https://dartpad.dartlang.org/"&gt;&lt;strong&gt;Dartpad&lt;/strong&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Previous post
&lt;/h2&gt;

&lt;p&gt;If you're interested in more posts like this, you can check out my others post about Dart.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://dev.to/codingpizza/variables-in-dart-4j63"&gt;Variables&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://dev.to/codingpizza/functions-in-dart-175b"&gt;Functions&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://dev.to/codingpizza/parameters-in-dart-3hm0"&gt;Parameters&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://dev.to/codingpizza/control-flow-in-dart-3ep6"&gt;Control flow&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://dev.to/codingpizza/collections-in-dart-3c5p"&gt;Collections&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

</description>
      <category>beginners</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
