<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: disced</title>
    <description>The latest articles on DEV Community by disced (@dragosb).</description>
    <link>https://dev.to/dragosb</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%2F800324%2F9147895d-635b-48c3-be30-555c959fa601.png</url>
      <title>DEV Community: disced</title>
      <link>https://dev.to/dragosb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dragosb"/>
    <language>en</language>
    <item>
      <title>Lo Mejor De NestJS</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Wed, 19 Mar 2025 14:47:28 +0000</pubDate>
      <link>https://dev.to/dragosb/lo-mejor-de-nestjs-5160</link>
      <guid>https://dev.to/dragosb/lo-mejor-de-nestjs-5160</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;¿Por qué me gusta NestJS para el desarrollo backend con TypeScript?&lt;/li&gt;
&lt;li&gt;
Módulos en NestJS

&lt;ol&gt;
&lt;li&gt;Controladores&lt;/li&gt;
&lt;li&gt;Servicios&lt;/li&gt;
&lt;li&gt;Datos (Repositorios)&lt;/li&gt;
&lt;li&gt;Resumen&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Inyección de Dependencias

&lt;ol&gt;
&lt;li&gt;@Injectable&lt;/li&gt;
&lt;li&gt;Inyección en el constructor&lt;/li&gt;
&lt;li&gt;Inyección en propiedades&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Documentación oficial Módulos NestJS&lt;/li&gt;

&lt;li&gt;Documentación oficial Inyección de dependencias NestJS&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  ¿Por qué me gusta NestJS para el desarrollo backend con TypeScript?
&lt;/h2&gt;

&lt;p&gt;Si eres como yo y prefieres tener las cosas bien estructuradas y organizadas, es probable que también te gusten los lenguajes más estrictos, como TypeScript en lugar de JavaScript, o los frameworks que imponen una forma estándar de trabajar, como Angular en vez de React. Esto no significa que una opción sea mejor que otra, simplemente son diferentes enfoques, y personalmente me inclino más por este tipo de herramientas (aunque no descarto las demás).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recientemente he descubierto también &lt;a href="https://encore.dev" rel="noopener noreferrer"&gt;Encore.ts&lt;/a&gt;, creo que no es tan estructurado pero no lo he trabajado&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bajo esta premisa, NestJS me resulta atractivo porque proporciona una estructura clara y organizada para el desarrollo backend. A veces puede dar dolores de cabeza, su enfoque basado en principios sólidos como la inyección de dependencias y la arquitectura modular hace que el código sea más mantenible y escalable.&lt;/p&gt;

&lt;p&gt;A continuación, haré un breve resumen de la arquitectura básica que sigue NestJS.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Módulos en NestJS
&lt;/h2&gt;

&lt;p&gt;La idea principal en NestJS es dividir el proyecto en módulos. Pero, ¿qué es exactamente un módulo?&lt;br&gt;
Lo podemos entender como una unidad fundamental que encapsula una parte de la lógica de negocio.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si el requisito del cliente es desarrollar un blog con entradas y usuarios, en un primer análisis podríamos identificar dos módulos principales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Módulo de Usuarios&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Módulo de Entradas&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada módulo, a su vez, se organiza en distintos componentes esenciales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Controlador&lt;/strong&gt;: Maneja las solicitudes HTTP y define los endpoints del módulo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Servicio&lt;/strong&gt;: Contiene la lógica de negocio y actúa como intermediario entre el controlador y los datos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datos&lt;/strong&gt;: Generalmente representados por entidades, repositorios o modelos que interactúan con la base de datos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para definir un módulo se hace de la siguiente forma:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypk6z1xr4otxsqst4121.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypk6z1xr4otxsqst4121.png" alt="NestJS Module definition" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Controladores
&lt;/h3&gt;

&lt;p&gt;El controlador de un módulo es una &lt;strong&gt;clase&lt;/strong&gt; cuya única función es &lt;strong&gt;exponer los endpoints&lt;/strong&gt; del módulo e &lt;strong&gt;interactuar&lt;/strong&gt; con el &lt;strong&gt;cliente&lt;/strong&gt;. Se encarga de recibir las requests y devolver las responses, pero &lt;strong&gt;no implementa ninguna lógica de negocio&lt;/strong&gt;.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;El controller debe implementar el servicio, pero en el anterior ejemplo no lo usamos para que sea más sencillo de comprender.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Servicios
&lt;/h3&gt;

&lt;p&gt;Los servicios son &lt;strong&gt;clases&lt;/strong&gt; encargadas de &lt;strong&gt;ejecutar&lt;/strong&gt; la &lt;strong&gt;lógica de negocio&lt;/strong&gt;. Reciben los datos desde el controlador, los procesan y realizan las operaciones necesarias antes de devolver una respuesta. &lt;/p&gt;

&lt;p&gt;Son el núcleo de la aplicación y permiten mantener una arquitectura limpia y bien organizada.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;El servicio implementará la clase encargada de acceder a los datos, en este caso no lo hacemos para que sea más sencillo de entender. Pero el &lt;strong&gt;servicio nunca accederá&lt;/strong&gt; directamente a los datos.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Datos (Repositorios)
&lt;/h3&gt;

&lt;p&gt;Los datos o repositorios son &lt;strong&gt;clases&lt;/strong&gt; &lt;strong&gt;dedicadas&lt;/strong&gt; exclusivamente** al acceso y gestión de datos**. Pueden obtener información desde bases de datos, ficheros, otras APIs, o cualquier otra fuente externa. &lt;/p&gt;

&lt;p&gt;Su función es desacoplar la lógica de acceso a datos del resto de la aplicación, facilitando la mantenibilidad y escalabilidad del proyecto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En este caso no proporcionaré un ejemplo, ya que la implementación de la clase varía dependiendo de la biblioteca utilizada &lt;em&gt;(mongoose, typeorm, prisma)&lt;/em&gt; y la base de datos empleada.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Resumen
&lt;/h3&gt;

&lt;p&gt;En un módulo de NestJS, contamos con tres clases bien diferenciadas, cada una con una responsabilidad específica:&lt;/p&gt;

&lt;p&gt;Cada clase cumple su función sin invadir la responsabilidad de las demás, &lt;strong&gt;manteniendo una separación clara de responsabilidades&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Además, siguen una jerarquía en la que cada capa solo interactúa con la inferior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;El &lt;strong&gt;controlador utiliza el servicio&lt;/strong&gt;, pero el servicio no tiene conocimiento del controlador.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El &lt;strong&gt;servicio utiliza los repositorios&lt;/strong&gt; o fuentes de datos, pero estos no conocen al servicio.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Te habrás dado cuenta de que esta estructura sigue los principios de &lt;strong&gt;Domain-Driven Design&lt;/strong&gt; (DDD) y &lt;strong&gt;Clean Architecture&lt;/strong&gt;. Esto es una gran ventaja, ya que nos permite mantener una clara separación de responsabilidades, lo que facilita la organización del código y mejora la testabilidad de cada componente de forma independiente.&lt;/p&gt;
&lt;h2&gt;
  
  
  Inyección de Dependencias
&lt;/h2&gt;

&lt;p&gt;Otra de las características fundamentales de NestJS es su sistema de &lt;strong&gt;inyección de dependencias&lt;/strong&gt;, un concepto &lt;strong&gt;utilizado&lt;/strong&gt; en frameworks como &lt;strong&gt;Spring Boot&lt;/strong&gt;. Este mecanismo es clave para lograr una mayor flexibilidad y modularidad en nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Al aplicar este patrón, &lt;strong&gt;evitamos&lt;/strong&gt; la necesidad de &lt;strong&gt;instanciar manualmente las clases&lt;/strong&gt;. Es decir, nunca crearemos objetos con &lt;code&gt;new UserService()&lt;/code&gt;. En su lugar, simplemente indicamos que necesitamos una clase del tipo &lt;code&gt;UserService&lt;/code&gt;, y &lt;strong&gt;NestJS&lt;/strong&gt; se encargará de &lt;strong&gt;gestionar su instancia&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;De forma predeterminada las clases que inyectemos son tipo &lt;a href="https://docs.nestjs.com/fundamentals/injection-scopes#provider-scope" rel="noopener noreferrer"&gt;Singleton&lt;/a&gt; (&lt;code&gt;DEFAULT&lt;/code&gt;), hay que tenerlo en cuenta en ciertas ocasiones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cuando una clase es requerida, Nest verifica en su registro interno si ya existe una instancia disponible. Si es así, la reutiliza; de lo contrario, la crea automáticamente. Por defecto, todas las clases inyectadas son Singleton, lo que significa que se instancian una única vez y se comparten en toda la aplicación, optimizando el uso de recursos.&lt;/p&gt;

&lt;p&gt;Este enfoque no solo hace que el código sea más limpio y mantenible, sino que también facilita la escalabilidad del proyecto.&lt;/p&gt;
&lt;h3&gt;
  
  
  Injectable
&lt;/h3&gt;

&lt;p&gt;Cualquier clase anotada con &lt;code&gt;@Injectable&lt;/code&gt; es gestionada por el contenedor de dependencias (IoC) de NestJS. Si, por ejemplo, tenemos una clase de utilidades que queremos usar en el módulo de User, debemos importar dicha clase en el módulo y declararla dentro del array de providers. Una vez hecho esto, ya podremos aprovechar la inyección de dependencias.&lt;/p&gt;

&lt;p&gt;Existen dos formas principales de inyectar dependencias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;En el constructor&lt;/strong&gt;: la forma recomendada y por defecto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;En las propiedades&lt;/strong&gt;: utilizada en casos específicos, como cuando trabajamos con herencia y necesitamos llamar al método super() de la clase padre.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Inyección en el constructor
&lt;/h3&gt;

&lt;p&gt;Esta es la forma más común y sencilla de hacerlo. Cuando encuentres una clase con un constructor que tenga uno o más argumentos, estos generalmente serán otras clases (o valores) que NestJS inyecta automáticamente en esa clase.&lt;/p&gt;

&lt;p&gt;En el ejemplo anterior, tenemos el controlador UserController y el servicio UserService. Según la arquitectura propuesta, el controlador debería utilizar el servicio. Para lograr esto, inyectamos el servicio en el constructor del controlador, y NestJS se encargará automáticamente del resto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq45cbjfrcqfhd2t17rcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq45cbjfrcqfhd2t17rcf.png" alt="NestJS Inyeccion en el constructor" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Inyección en propiedades
&lt;/h3&gt;

&lt;p&gt;Aunque menos común, esta técnica también es válida. La usamos en situaciones específicas, como cuando una clase hereda de otra y necesitamos llamar al método &lt;code&gt;super()&lt;/code&gt; del padre. Esto evita que tengamos que modificar ambas clases. Para hacerlo, usamos el decorador &lt;code&gt;@Inject()&lt;/code&gt; y le pasamos el token o la clase que queremos inyectar en la propiedad.&lt;/p&gt;

&lt;p&gt;Esta opción también es válida para la inyección:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7n6zyck3awg4j7lbf39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7n6zyck3awg4j7lbf39.png" alt="Inyeccion en propiedades NestJS" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Documentación oficial Módulos NestJS
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://docs.nestjs.com/modules" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnestjs.com%2Fimg%2Fnest-og.png" height="418" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://docs.nestjs.com/modules" rel="noopener noreferrer" class="c-link"&gt;
          Documentation | NestJS - A progressive Node.js framework
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.nestjs.com%2Fassets%2Ffavicons%2Ffavicon-32x32.png" width="32" height="32"&gt;
        docs.nestjs.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Documentación oficial Inyección de dependencias NestJS
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://docs.nestjs.com/providers#dependency-injection" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnestjs.com%2Fimg%2Fnest-og.png" height="418" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://docs.nestjs.com/providers#dependency-injection" rel="noopener noreferrer" class="c-link"&gt;
          Documentation | NestJS - A progressive Node.js framework
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.nestjs.com%2Fassets%2Ffavicons%2Ffavicon-32x32.png" width="32" height="32"&gt;
        docs.nestjs.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>nestjs</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Arquitectura Limpia</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Sun, 15 Oct 2023 09:50:23 +0000</pubDate>
      <link>https://dev.to/dragosb/arquitectura-limpia-2e6j</link>
      <guid>https://dev.to/dragosb/arquitectura-limpia-2e6j</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introducción&lt;/li&gt;
&lt;li&gt;Tipos&lt;/li&gt;
&lt;li&gt;
Estructura

&lt;ul&gt;
&lt;li&gt;Enterprise Business Rules&lt;/li&gt;
&lt;li&gt;Application Business Rules&lt;/li&gt;
&lt;li&gt;Interface Adapters&lt;/li&gt;
&lt;li&gt;Frameworks and Drivers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Regla de la dependencia&lt;/li&gt;

&lt;li&gt;Diagrama desglosado&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;En este post no voy a explicar para que utilizar la Arquitectura Limpia, ni que ventajas tiene ni las características. &lt;/p&gt;

&lt;p&gt;Lo que sí voy a explicar es &lt;strong&gt;como utilizarlo&lt;/strong&gt; y que contiene cada capa. &lt;/p&gt;

&lt;p&gt;Lo que pretendo es que tú como lector no tengas que recurrir a tantas fuentes como yo para saber poner en práctica el concepto, que en última instancia, es lo más importante sobre este tema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tipos
&lt;/h2&gt;

&lt;p&gt;Seguramente te suenen cosas como &lt;strong&gt;DDD&lt;/strong&gt;, &lt;strong&gt;Arquitectura Hexagonal&lt;/strong&gt;, &lt;strong&gt;Arquitectura Onion&lt;/strong&gt;, etc.&lt;/p&gt;

&lt;p&gt;Todos estos ejemplos tienen que ver en como estructurar el código de nuestros programas. Son distintos tipos de arquitecturas de software. &lt;/p&gt;

&lt;p&gt;El problema que yo he encontrado a medida que aprendía sobre el tema, es que, en multitud de ocasiones se explica de forma muy general los conceptos &lt;em&gt;(definiciones muy de Wikipedia)&lt;/em&gt;, en otras ocasiones me he encontrado que se mezclan términos de una arquitectura a otra o se cambia el nombre de las cosas y todos estos hechos al final confunden mucho.&lt;/p&gt;

&lt;p&gt;Dicho esto, yo explicaré solamente &lt;strong&gt;Clean Architecture&lt;/strong&gt; propuesto por &lt;strong&gt;Robert C. Martin&lt;/strong&gt; &lt;em&gt;(el Tío Bob)&lt;/em&gt;. Como es la &lt;strong&gt;estructura&lt;/strong&gt;, que &lt;strong&gt;contiene cada capa&lt;/strong&gt; y poniendo algunos &lt;strong&gt;ejemplos reales&lt;/strong&gt; para cada capa. También he desglosado el gráfico para hacerlo como una especie de cheatsheet que está al final del artículo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura
&lt;/h2&gt;

&lt;p&gt;El modelo propuesto por el tío Bob imagino que lo habrás visto en multitud de ocasiones y también todas sus variaciones &lt;em&gt;(al final todas las arquitecturas tienen similitudes)&lt;/em&gt; y es el que tenemos en la siguiente imagen:&lt;/p&gt;

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

&lt;p&gt;Yo cuando veía esta imagen aun conociendo Clean Architecture me costaba entenderla y dependiendo del stack que utilices puedes entenderla aún menos.&lt;/p&gt;

&lt;p&gt;Los nombres reales de cada círculo o capa son los de la leyenda de la derecha y no lo que hay en cada círculo 💥.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yo no entendía que era que, por muchas definiciones de &lt;code&gt;Entities&lt;/code&gt; que leyera, o &lt;code&gt;Enterprise Bussiness Rules&lt;/code&gt; seguía sin comprenderlo porque todo el mundo usa la misma definición.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es decir, que lo que está escrito dentro de los círculos son simplemente ejemplos &lt;em&gt;(lo menciono por si a alguien le ha pasado como a mí)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;La estructura es la siguiente &lt;em&gt;(desde dentro hacia afuera)&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enterprise Business Rules&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Business Rules&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interface Adapters&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frameworks and Drivers&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Perfecto! no se entiende nada o muy poco.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enterprise Business Rules
&lt;/h3&gt;

&lt;p&gt;En este círculo vas a almacenar cosas como: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;interface&lt;/code&gt; &lt;em&gt;(typescript)&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data class&lt;/code&gt; &lt;em&gt;(kotlin)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;record&lt;/code&gt; &lt;em&gt;(c#)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;record&lt;/code&gt; &lt;em&gt;(java)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Te habrás dado cuenta de que solamente se engloban &lt;strong&gt;clases de datos&lt;/strong&gt; o en algún casual una clase con atributos y métodos, pero que &lt;strong&gt;no salga al exterior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Que no salga al exterior quiere decir que no deberá utilizar cosas como la base de datos, APIs o cualquier otra conexión con elementos externos.&lt;/p&gt;

&lt;p&gt;Estas clases solo se conocen a ellas mismas, son como Narciso, no ven más allá de su ombligo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Business Rules
&lt;/h3&gt;

&lt;p&gt;En este círculo guardarás el &lt;strong&gt;código relacionado con la aplicación&lt;/strong&gt;, API, web o lo que sea que programes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Si mi aplicación cuenta con un &lt;strong&gt;carrito de compra&lt;/strong&gt;, aquí harás las &lt;strong&gt;operaciones&lt;/strong&gt; &lt;strong&gt;necesarias&lt;/strong&gt; con el &lt;strong&gt;carrito de compra&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Si mi backend debe &lt;strong&gt;generar&lt;/strong&gt; un &lt;strong&gt;PDF&lt;/strong&gt; lo harás aquí.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Si la app calcula cuantos coches pueden entrar en un aparcamiento &lt;em&gt;(todavía inexistente el aparcamiento)&lt;/em&gt; conociendo los m² del aparcamiento, el &lt;strong&gt;cálculo&lt;/strong&gt; lo &lt;strong&gt;harás&lt;/strong&gt; &lt;strong&gt;aquí&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Algunos ejemplos concretos de que deberás englobar aquí son los siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;controllers&lt;/code&gt; &lt;em&gt;(expressjs)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;service&lt;/code&gt; &lt;em&gt;(java spring boot)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Servicios &lt;em&gt;(.net)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Injectable&lt;/code&gt; &lt;em&gt;(nestjs)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;En muchos programas las 2 capas internas (Enterprise Business Rules y Application Business Rules) se engloban en una única que la llaman Dominio o Domain.&lt;/p&gt;

&lt;p&gt;El nombre se refiere al núcleo del negocio o al propósito principal de la aplicación.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Interface Adapters
&lt;/h3&gt;

&lt;p&gt;Este círculo funciona como &lt;strong&gt;puente entre el anterior y el siguiente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El círculo contendrá cosas como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;router&lt;/code&gt; &lt;em&gt;(expressjs)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;controller&lt;/code&gt; &lt;em&gt;(java spring boot)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ApiController&lt;/code&gt; &lt;em&gt;(.net)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;controller&lt;/code&gt; &lt;em&gt;(nestjs)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;También se utilizarán los &lt;strong&gt;repositorios&lt;/strong&gt; inyectándolos por ejemplo en los &lt;strong&gt;controladores&lt;/strong&gt; o &lt;strong&gt;servicios&lt;/strong&gt;, así el controlador/servicio podrá utilizar la base de datos pero no directamente. O podrá hacer peticiones a una API externa.&lt;/p&gt;

&lt;h4&gt;
  
  
  Disclaimer ⚠
&lt;/h4&gt;

&lt;p&gt;Como harás observado en &lt;strong&gt;ExpressJS&lt;/strong&gt; existen &lt;strong&gt;Controllers y Routers&lt;/strong&gt; y en los demás framworks a estos elementos se les llama &lt;strong&gt;Servicios y Controllers&lt;/strong&gt;, pero vienen a ser lo mismo con distintos nombres.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ExpressJS&lt;/th&gt;
&lt;th&gt;Spring Boot&lt;/th&gt;
&lt;th&gt;.Net&lt;/th&gt;
&lt;th&gt;NestJS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Controller&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Servicios&lt;/td&gt;
&lt;td&gt;Injectables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Controller&lt;/td&gt;
&lt;td&gt;ApiController&lt;/td&gt;
&lt;td&gt;Controller&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Frameworks and Drivers
&lt;/h3&gt;

&lt;p&gt;Este puede llegar a ser algo confuso, ya que engloba cosas como la base de datos y la web y esto es raro porque al verlo así, en nuestra cabeza ponemos en el mismo nivel el código de la base de datos y el de la web.&lt;/p&gt;

&lt;p&gt;Aquí guardarás cosas como los DTOs, las consultas a base de datos, las tablas, el cliente web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regla de la dependencia
&lt;/h2&gt;

&lt;p&gt;Una vez entendemos la estructura debemos entender como usar los elementos entre sí. Para utilizar de forma correcta cada elemento &lt;strong&gt;siempre nos guiaremos por la Regla de la Dependencia&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Y esta regla en esencia es que los elementos del interior se conocen solamente a ellos mismos y a nadie de fuera.&lt;/p&gt;

&lt;p&gt;Es decir, que los círculos de fuera siempre van a conocer &lt;em&gt;(y usar)&lt;/em&gt; a los de dentro y nunca al revés.&lt;/p&gt;

&lt;p&gt;Por lo tanto, podemos afirmar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Las &lt;strong&gt;consultas a bases de datos&lt;/strong&gt; pueden hacer uso de un &lt;code&gt;data class&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ya que se encuentran en Frameworks &amp;amp; Drivers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Un &lt;code&gt;controller&lt;/code&gt; &lt;em&gt;(expressjs)&lt;/em&gt; puede usar un &lt;code&gt;interface&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El controller en este caso forma parte de Application Business Rules&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Un &lt;code&gt;ApiController&lt;/code&gt; usará los servicios.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forma parte de Interface Adapters&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pero nunca al revés, desde dentro hacia afuera:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En una &lt;code&gt;data class&lt;/code&gt; &lt;strong&gt;nunca&lt;/strong&gt; se utilizará un &lt;code&gt;controller&lt;/code&gt; o la base de datos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Diagrama desglosado
&lt;/h2&gt;

&lt;p&gt;Comprendiendo lo anterior he intentado desglosar el gráfico y hacerlo más entendible para mí con la esperanza de que para ti también sea más entendible:&lt;/p&gt;

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

</description>
      <category>architecture</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>ViewModel en Android</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Fri, 15 Sep 2023 08:32:07 +0000</pubDate>
      <link>https://dev.to/dragosb/viewmodel-en-android-3mp5</link>
      <guid>https://dev.to/dragosb/viewmodel-en-android-3mp5</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Qué es&lt;/li&gt;
&lt;li&gt;Para qué sirve&lt;/li&gt;
&lt;li&gt;Beneficios de uso&lt;/li&gt;
&lt;li&gt;Ciclo de vida&lt;/li&gt;
&lt;li&gt;
Implementación básica

&lt;ul&gt;
&lt;li&gt;Dependencias&lt;/li&gt;
&lt;li&gt;Clase ViewModel&lt;/li&gt;
&lt;li&gt;Composable&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Implementación con DI&lt;/li&gt;

&lt;li&gt;ViewModel Cheatsheet&lt;/li&gt;

&lt;li&gt;Referencias&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Qué es
&lt;/h2&gt;

&lt;p&gt;El &lt;code&gt;ViewModel&lt;/code&gt; en Android forma parte del patrón arquitectónico &lt;code&gt;Model-View-ViewModel&lt;/code&gt;, siendo éste el ultimo de dicho patrón.&lt;/p&gt;

&lt;p&gt;Es decir que es una forma de organizar el código para que sea mas entendible, mas estructurado y mas testable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para qué sirve
&lt;/h2&gt;

&lt;p&gt;La idea fundamental es tener la parte lógica y las variables fuera de la vista &lt;em&gt;(fuera del codigo de jetpack compose por ejemplo)&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Por ejemplo si vamos a hacer una petición a una API HTTP u obtener datos de una base de datos, esta funcionalidad deberíamos realizarla desde el ViewModel. De esta manera conseguimos que en la vista solo se rendericen datos para que el usuario los vea, &lt;strong&gt;en ningún momento tenemos lógica&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El &lt;strong&gt;ViewModel&lt;/strong&gt; &lt;strong&gt;no debe interactuar&lt;/strong&gt; directamente con una &lt;strong&gt;API&lt;/strong&gt; o una &lt;strong&gt;base de datos&lt;/strong&gt;, utilizaremos el patrón &lt;strong&gt;Repository&lt;/strong&gt;. Solo debe utilizar el repositorio, obtener los datos en "crudo" y realizar las modificaciones oportunas para enviarlas a la view.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Beneficios de uso
&lt;/h2&gt;

&lt;p&gt;Las ventajas principales de utilizar &lt;code&gt;ViewModel&lt;/code&gt; en Android son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El ciclo de vida del ViewModel tiene mas alcance que un &lt;code&gt;Activity&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Esto nos permite almacenar datos &lt;em&gt;(variables)&lt;/em&gt; y si hay un cambio en el dispositivo, como rotación de pantalla, los datos seguirán presentes en el ViewModel. Conserva el estado de las vistas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Nos proporciona acceso a la lógica empresarial&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ciclo de vida
&lt;/h2&gt;

&lt;p&gt;El &lt;code&gt;ViewModel&lt;/code&gt; no consta de un ciclo de vida tradicional como el que encontramos en las &lt;code&gt;Activity&lt;/code&gt; o &lt;code&gt;Fragment&lt;/code&gt;. En su lugar, tiene un alcance específico dentro del ciclo de vida, y este alcance es más extenso.&lt;/p&gt;

&lt;p&gt;A diferencia del ciclo de vida de una &lt;code&gt;Activity&lt;/code&gt; o &lt;code&gt;Fragment&lt;/code&gt;, el &lt;code&gt;ViewModel&lt;/code&gt; ofrece un alcance más amplio. Esta particularidad nos permite conservar datos en el &lt;code&gt;ViewModel&lt;/code&gt; a pesar de que ocurran cambios en la interfaz, como rotaciones de pantalla o si la &lt;code&gt;Activity&lt;/code&gt; pasa por cambios de estado, entre otros eventos.&lt;/p&gt;

&lt;p&gt;La siguiente imagen muestra el flujo de una &lt;code&gt;Activity&lt;/code&gt; y los métodos que se activan en respuesta a diversos eventos. A la derecha, se puede observar el amplio alcance del &lt;code&gt;ViewModel&lt;/code&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Implementación básica
&lt;/h2&gt;

&lt;p&gt;En este ejemplo voy a mostrar como implementar el &lt;code&gt;ViewModel&lt;/code&gt; junto a &lt;code&gt;Jetpack Compose&lt;/code&gt; de forma básica. &lt;/p&gt;

&lt;p&gt;También haré uso de elementos como &lt;code&gt;MutableLiveData&lt;/code&gt; y &lt;code&gt;LiveData&lt;/code&gt; &lt;em&gt;(son implementaciones para clases observables, es decir que nos subscribimos a la clase y si ocurre un cambio, reaccionamos haciendo lo que sea)&lt;/em&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Dependencias
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.android.com/jetpack/androidx/releases/lifecycle?hl=es-419#kts" rel="noopener noreferrer"&gt;Link oficial&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  app/build.gradle.kts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lifecycle_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2.6.1"&lt;/span&gt;  
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Clase ViewModel
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingViewModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="cm"&gt;/*  
     * Variable (_randomvm) que observamos y podemos modificar, se usa a nivel interno en     * los ViewModels     */&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_randomvm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomvm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_randomvm&lt;/span&gt;  

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;_randomvm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;En el &lt;code&gt;ViewModel&lt;/code&gt; hemos creado dos variables, ambas son clases observables. La única diferencia es: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MutableLiveData&lt;/code&gt; nos permite modificar el valor que almacena. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LiveData&lt;/code&gt; no nos permite modificar el valor almacenado.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Siempre nos interesa que solo el &lt;code&gt;ViewModel&lt;/code&gt; modifique los valores de las variables observables. Por este motivo utilizamos &lt;code&gt;MutableLiveData&lt;/code&gt; de forma privada y &lt;code&gt;LiveData&lt;/code&gt; de forma pública. Así solo se cambia el contenido dentro del &lt;code&gt;ViewModel&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Al instanciarse la clase &lt;code&gt;GreetingViewModel&lt;/code&gt; se ejecutará el método &lt;code&gt;init&lt;/code&gt;. Éste método genera un número aleatorio y modifica el valor del &lt;code&gt;MutableLiveData&lt;/code&gt;. &lt;code&gt;randomvm&lt;/code&gt; al ser igual que &lt;code&gt;MutableLiveData&lt;/code&gt;, también cambiará su valor, y allá donde se observe la variable, se reaccionará a los cambios.&lt;/p&gt;
&lt;h4&gt;
  
  
  Composable
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GreetingViewModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomFromVM&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randomvm&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"From ViewModel: ${randomFromVM.value}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"From local composable's scope: $random"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello $name!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt;  
    &lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;En el composable instanciamos el viewModel utilizando el metodo &lt;code&gt;viewModel()&lt;/code&gt; &lt;em&gt;(que se encuentra en las dependencias instaladas en el primer paso)&lt;/em&gt; como argumento de la función, y dentro del composable ya podemos utilizar los métodos y atributos públicos.&lt;/p&gt;

&lt;p&gt;Las variables que tenemos son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;randomFromVM&lt;/code&gt;: es lo mismo que la variable &lt;code&gt;randomvm&lt;/code&gt; del viewmodel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;random&lt;/code&gt;: una variable en el ámbito local de la función.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si ejecutamos el programa, vemos que cada vez que rotemos el dispositivo el valor de &lt;code&gt;random&lt;/code&gt; será diferente, y el valor de &lt;code&gt;randomFromVM&lt;/code&gt; será siempre el mismo, ya que este dato se almacena en el viewmodel y este tiene un mayor alcance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7363qiwn0stlim1nz8ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7363qiwn0stlim1nz8ip.png" alt="Salida logcat" width="598" height="212"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementación con DI
&lt;/h2&gt;

&lt;p&gt;Al utilizar inyección de dependencias con Hilt la implementación de un viewmodel es diferente, ya que deberemos proveer el ViewModel a hilt y después utilizar un método propio de hilt.&lt;/p&gt;

&lt;p&gt;La única diferencia es que anotamos la clase con &lt;code&gt;@HiltViewModel&lt;/code&gt; y en el &lt;code&gt;@Composable&lt;/code&gt; lo inyectamos mediante el método &lt;code&gt;hiltViewModel()&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Clase ViewModel
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltViewModel&lt;/span&gt;  
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingViewModel&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_randomvm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomvm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_randomvm&lt;/span&gt;  

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;_randomvm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;

&lt;h4&gt;
  
  
  Composable
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GreetingViewModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hiltViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomFromVM&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randomvm&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"From ViewModel: ${randomFromVM.value}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"From local composable's scope: $random"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello $name!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt;  
    &lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Para implementar el viewModel junto a Hilt es necesario agregar nuevas dependencias en gradle, yo en el ejemplo no lo he hecho, pero la documentación oficial es la siguiente: &lt;a href="https://developer.android.com/jetpack/androidx/releases/hilt?hl=es-419#hilt-navigation-compose_version_100_2" rel="noopener noreferrer"&gt;Androidx Releases&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  ViewModel Cheatsheet
&lt;/h2&gt;

&lt;p&gt;Adjunto una imagen de un cheat sheet de la documentación oficial de Android, dejo el &lt;a href="https://developer.android.com/images/topic/libraries/architecture/viewmodel-apis-cheatsheet.pdf" rel="noopener noreferrer"&gt;enlace al pdf web&lt;/a&gt;.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/topic/libraries/architecture/viewmodel?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.android.com%2Fstatic%2Fimages%2Fsocial%2Fandroid-developers.png%3Fhl%3Des-419" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/topic/libraries/architecture/viewmodel?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Descripción general de ViewModel  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          ViewModel te permite administrar los datos de tu IU de forma optimizada para ciclos de vida.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.gstatic.com%2Fdevrel-devsite%2Fprod%2Fv6bfb74446ce17cd0d3af9b93bf26e056161cb79c5a6475bd6a9c25286fcb7861%2Fandroid%2Fimages%2Ffavicon.svg" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>android</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Mi Guía De Commits📝</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Wed, 02 Aug 2023 09:41:27 +0000</pubDate>
      <link>https://dev.to/dragosb/mi-guia-de-commits-578g</link>
      <guid>https://dev.to/dragosb/mi-guia-de-commits-578g</guid>
      <description>&lt;ul&gt;
&lt;li&gt;📯 Introducción&lt;/li&gt;
&lt;li&gt;Estructura&lt;/li&gt;
&lt;li&gt;
Elementos

&lt;ul&gt;
&lt;li&gt;Tipo&lt;/li&gt;
&lt;li&gt;Ámbito&lt;/li&gt;
&lt;li&gt;Breve título&lt;/li&gt;
&lt;li&gt;Cuerpo&lt;/li&gt;
&lt;li&gt;Pie&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Prompt ChatGPT

&lt;ul&gt;
&lt;li&gt;Prompt&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Guía básica de como redacto los mensajes de los commits para saber que hace el commit y tener una estructura definida para los mismos. También saber que cambios se han realizado en el código sin tener que verlo.&lt;/p&gt;

&lt;p&gt;Está basada en &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt; que ésta a su vez se basa en la &lt;a href="https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines" rel="noopener noreferrer"&gt;guía de commits de Angular&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Estas dos anteriores guías o estándares yo no los sigo al pie de la letra, son una simple base la cual seguir pero si veo necesarios cambios para mi caso concreto, los implementaré, y tu deberías hacer lo mismo, adaptarlo para tu caso concreto y como mejor te funcione&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Estructura
&lt;/h2&gt;

&lt;p&gt;La estructura de los mensajes es la que vemos a continuación &lt;em&gt;(los elementos que van dentro de corchetes [] son opcionales)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;TIPO&amp;gt;&lt;/span&gt;([ámbito opcional]): &lt;span class="nt"&gt;&amp;lt;BREVE_TÍTULO&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;SALTO_DE_LINEA&amp;gt;&lt;/span&gt;
[CUERPO]
&lt;span class="nt"&gt;&amp;lt;SALTO_DE_LINEA&amp;gt;&lt;/span&gt;
[PIE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Elementos
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Tipo
&lt;/h3&gt;

&lt;p&gt;Indica de manera &lt;strong&gt;general&lt;/strong&gt; que &lt;strong&gt;hace&lt;/strong&gt; el &lt;strong&gt;commit&lt;/strong&gt; y es &lt;strong&gt;obligatorio&lt;/strong&gt;. En mi caso los tipos de commits que suelo utilizar son los siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;feat&lt;/code&gt;: indica que el commit implementa una nueva feature.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fix&lt;/code&gt; : indica la resolución de un fallo/bug/issue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs&lt;/code&gt;: indica cambios o nueva documentación.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refactor&lt;/code&gt;: indica que se ha refactorizado código, sin cambios en la funcionalidad.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;remove&lt;/code&gt; : indica que se ha eliminado algo del proyecto.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt; : indica cambios o nuevas implementaciones de tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Ámbito
&lt;/h3&gt;

&lt;p&gt;El ámbito va &lt;strong&gt;entre&lt;/strong&gt; &lt;strong&gt;paréntesis&lt;/strong&gt; después del tipo, y es &lt;strong&gt;opcional&lt;/strong&gt;. Hace referencia a una determinada parte del código, por ejemplo: &lt;em&gt;gui, database, hilt, di&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Breve título
&lt;/h3&gt;

&lt;p&gt;Es una &lt;strong&gt;breve descripción&lt;/strong&gt; de lo que &lt;strong&gt;hace el commit&lt;/strong&gt;, es &lt;strong&gt;obligatorio&lt;/strong&gt; y se deben usar verbos &lt;strong&gt;imperativos&lt;/strong&gt;, es decir que se debe leer de la siguiente manera:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;th&gt;Como se lee&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Modifica el boton de login&lt;/td&gt;
&lt;td&gt;Este commit modifica el boton de login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementa inyeccion de dependencias&lt;/td&gt;
&lt;td&gt;Este commit implementa la inyeccion de dependecias&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Evitar escribir commits en primera persona: He cambiado la forma de hacer login, he cambiado los colores...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Cuerpo
&lt;/h3&gt;

&lt;p&gt;Después del titulo insertar un &lt;strong&gt;salto de linea&lt;/strong&gt; y añadir el &lt;strong&gt;cuerpo&lt;/strong&gt;. Este elemento es opcional y se usa en el caso de querer dar mas información de lo que hace el commit.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Pie
&lt;/h3&gt;

&lt;p&gt;El pie debe ir seguido de un salto de linea y se utiliza para dar información sobre quien ha realizado el commit, quien lo ha revisado, cual es la issue que arregla. Yo por el momento no utilizo esta parte&lt;/p&gt;
&lt;h2&gt;
  
  
  Prompt ChatGPT
&lt;/h2&gt;

&lt;p&gt;Para redactar el commit de forma mas rápida yo utilizo ChatGPT donde le indico lo que quiero que haga &lt;em&gt;(escribir el commit)&lt;/em&gt; y a continuación le proporciono la salida del comando &lt;code&gt;git diff&lt;/code&gt; para que genere el mensaje. &lt;/p&gt;

&lt;p&gt;En Ubuntu la salida de &lt;code&gt;git diff&lt;/code&gt; la copio directamente al clipboard usando &lt;code&gt;xclip&lt;/code&gt; y después la pego en el chat.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dragos@home git diff | xclip &lt;span class="nt"&gt;-sel&lt;/span&gt; clip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Y si es windows, lo podemos hacer en &lt;code&gt;powershell&lt;/code&gt; de forma parecida:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Users\dragos&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clip&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Prompt
&lt;/h3&gt;

&lt;p&gt;En esta conversación te vas a comportar como desarrollador de software. Necesito que escribas los mensajes de los commits por mi. Te indicaré la forma en la que debes escribirlos.&lt;/p&gt;

&lt;p&gt;Características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Escribe los mensajes en inglés muy básico y de la manera mas corta posible.&lt;/li&gt;
&lt;li&gt;El mensaje debe hablar de lo que hace este commit, arregla, modifica, implementa, etc.&lt;/li&gt;
&lt;li&gt;Todo mensaje debe incluir la estructura que te proporcionaré a continuación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La estructura que debes seguir es la siguiente:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;tipo&amp;gt;([ámbito opcional]): &amp;lt;breve descripción&amp;gt;
&amp;lt;SALTO DE LINEA&amp;gt;
[Cuerpo]
&amp;lt;SALTO DE LINEA&amp;gt;
[pie]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Los tipos son los siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix&lt;/li&gt;
&lt;li&gt;feat&lt;/li&gt;
&lt;li&gt;remove&lt;/li&gt;
&lt;li&gt;ui&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;li&gt;refactor&lt;/li&gt;
&lt;li&gt;docs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplos:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat(api): send an email to the customer when a product is shipped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Yo te pasare la salida del comando git diff y tu deberas generar el commit teniendo en cuenta todo lo anterior. No hagas nada mas aparte de generar el mensaje del commit, no respondas a nada mas y no escribas nada mas. Deberas ceñirte en todo momento solo a generar el commit.&lt;br&gt;
Ten en cuenta también lo siguiente:&lt;/p&gt;

&lt;p&gt;The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in &lt;a href="https://www.ietf.org/rfc/rfc2119.txt" rel="noopener noreferrer"&gt;RFC 2119&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Commits MUST be prefixed with a type, which consists of a noun, &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, etc., followed by the OPTIONAL scope, OPTIONAL &lt;code&gt;!&lt;/code&gt;, and REQUIRED terminal colon and space.&lt;/li&gt;
&lt;li&gt;The type &lt;code&gt;feat&lt;/code&gt; MUST be used when a commit adds a new feature to your application or library.&lt;/li&gt;
&lt;li&gt;The type &lt;code&gt;fix&lt;/code&gt; MUST be used when a commit represents a bug fix for your application.&lt;/li&gt;
&lt;li&gt;A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., &lt;code&gt;fix(parser):&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., &lt;em&gt;fix: array parsing issue when multiple spaces were contained in string&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.&lt;/li&gt;
&lt;li&gt;A commit body is free-form and MAY consist of any number of newline separated paragraphs.&lt;/li&gt;
&lt;li&gt;One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a &lt;code&gt;:&amp;lt;space&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;space&amp;gt;#&lt;/code&gt; separator, followed by a string value (this is inspired by the &lt;a href="https://git-scm.com/docs/git-interpret-trailers" rel="noopener noreferrer"&gt;git trailer convention&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A footer’s token MUST use &lt;code&gt;-&lt;/code&gt; in place of whitespace characters, e.g., &lt;code&gt;Acked-by&lt;/code&gt; (this helps differentiate the footer section from a multi-paragraph body). An exception is made for &lt;code&gt;BREAKING CHANGE&lt;/code&gt;, which MAY also be used as a token.&lt;/li&gt;
&lt;li&gt;A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed.&lt;/li&gt;
&lt;li&gt;Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer.&lt;/li&gt;
&lt;li&gt;If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., &lt;em&gt;BREAKING CHANGE: environment variables now take precedence over config files&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If included in the type/scope prefix, breaking changes MUST be indicated by a &lt;code&gt;!&lt;/code&gt; immediately before the &lt;code&gt;:&lt;/code&gt;. If &lt;code&gt;!&lt;/code&gt; is used, &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; MAY be omitted from the footer section, and the commit description SHALL be used to describe the breaking change.&lt;/li&gt;
&lt;li&gt;Types other than &lt;code&gt;feat&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt; MAY be used in your commit messages, e.g., &lt;em&gt;docs: update ref docs.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.&lt;/li&gt;
&lt;li&gt;BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.conventionalcommits.org%2Fimg%2Fgit-flow--welcome.png" height="1509" class="m-0" width="351"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer" class="c-link"&gt;
          Conventional Commits
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          A specification for adding human and machine readable meaning to commit messages
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
        conventionalcommits.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/angular/angular/blob/22b96b96902e1a42ee8c5e807720424abad3082a/CONTRIBUTING.md#commit" rel="noopener noreferrer"&gt;Angular Commit Guide&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>TDD Sencillo</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Mon, 17 Jul 2023 11:00:58 +0000</pubDate>
      <link>https://dev.to/dragosb/tdd-sencillo-2c9n</link>
      <guid>https://dev.to/dragosb/tdd-sencillo-2c9n</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Introducción&lt;/li&gt;
&lt;li&gt;Qué es el TDD&lt;/li&gt;
&lt;li&gt;Qué nos ofrece&lt;/li&gt;
&lt;li&gt;Para qué utilizarlo&lt;/li&gt;
&lt;li&gt;
Cómo se pone en marcha

&lt;ul&gt;
&lt;li&gt;
Las Tres Leyes

&lt;ul&gt;
&lt;li&gt;Primera ley&lt;/li&gt;
&lt;li&gt;Segunda ley&lt;/li&gt;
&lt;li&gt;Tercera ley&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

Cómo funciona en la práctica

&lt;ul&gt;
&lt;li&gt;Ciclo uno&lt;/li&gt;
&lt;li&gt;Ciclo dos&lt;/li&gt;
&lt;li&gt;Ciclo tres&lt;/li&gt;
&lt;li&gt;Ciclo cuatro&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Referencias&lt;/li&gt;

&lt;/ul&gt;




&lt;h1&gt;
  
  
  Introducción
&lt;/h1&gt;

&lt;p&gt;Este post lo he basado en el libro del Tio Bob &lt;em&gt;(Robert C. Martin)&lt;/em&gt;, &lt;strong&gt;La artesanía del código limpio&lt;/strong&gt;. Es una lectura muy recomendable ya que amplía muchos conceptos y se desarrollan de forma más extensa de lo que yo pretendo con este post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si te apasiona tanto como a mi el desarrollo de software, te darás cuenta que siempre vas a querer ser mejor desarrollador/a, por lo tanto llegarás a la conclusión de que el TDD aumentará tu habilidad en este sentido y vas a querer ponerlo en práctica. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Qué Es El TDD
&lt;/h1&gt;

&lt;p&gt;Es una forma más de escribir código, podemos decir que es una metodología a la hora de programar. El enfoque principal de este proceso son los &lt;em&gt;(temidos)&lt;/em&gt; tests, pero no es para tanto, además, nos ofrece muchas ventajas. &lt;/p&gt;

&lt;h1&gt;
  
  
  Qué Nos Ofrece
&lt;/h1&gt;

&lt;p&gt;Las ventajas que nos ofrece esta metodología de programar las podemos ver en la siguiente lista:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tener un código &lt;strong&gt;fácil&lt;/strong&gt; de &lt;strong&gt;leer&lt;/strong&gt; y &lt;strong&gt;entender&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tener un código &lt;strong&gt;poco interconectado&lt;/strong&gt; entre sí.&lt;/li&gt;
&lt;li&gt;Tener un código &lt;strong&gt;corto&lt;/strong&gt; y muy &lt;strong&gt;segmentado&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tener un código &lt;strong&gt;fácil&lt;/strong&gt; de &lt;strong&gt;testear&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Asegurarnos que nuestro código &lt;strong&gt;funciona bien&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tener un código &lt;strong&gt;escalable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;En ocasiones se llega al desarrollo de algoritmos complejos que sin realizar TDD es difícil llegar a la misma solución.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Para Qué Utilizarlo
&lt;/h1&gt;

&lt;p&gt;Los programadores lo utilizamos para  asegurar que nuestro trabajo está bien hecho y no falla.&lt;/p&gt;

&lt;p&gt;En el peor de los casos se utiliza para evitar muertes &lt;em&gt;(como bien ha ocurrido en el pasado por fallos de software, Boeing, Tesla...)&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Cómo Se Pone En Marcha
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Las Tres Leyes
&lt;/h2&gt;

&lt;p&gt;Para entender y aplicar el TDD se describe mediante 3 leyes o principios básicos que siempre debemos seguir para llevarlo a la práctica.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;En mi caso lo entendí al leer dichas leyes y ver ejemplos.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Primera Ley
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No escribir nunca un código de producción hasta haber escrito una prueba que falle debido a la falta de dicho código.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos a testear la clase persona por ejemplo, pero en nuestro desarrollo de momento no existe dicha clase, lo que haremos será escribir un test que instancie un objeto de la clase persona.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segunda Ley
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Escribir de un test lo mínimo posible para conseguir que falle o que no compile o ejecute. Resolver el fallo escribiendo código de producción.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En el ejemplo, escribimos una línea de código y el test fallará (no existe la clase persona). A continuación, como hemos escrito lo mínimo posible en el test, ahora escribimos código de producción para que pase la prueba, por lo tanto creamos una clase persona.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tercera Ley
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No escribir más código de producción que el que sea suficiente para pasar la prueba que falla en ese momento. Una vez ha pasado la prueba, escribimos más código de prueba *(volver a la primera ley)&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Para pasar la prueba solo se crea la clase persona y se ejecuta el test, debería de funcionar, entonces ahora hay que escribir otra prueba. Por ejemplo utilizar un método de la clase persona, &lt;code&gt;setName&lt;/code&gt; por ejemplo. Esta nueva prueba fallará, esto es bueno y es lo que esperamos que ocurra. Ahora volvemos a la primera ley.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tercera Ley*
&lt;/h3&gt;

&lt;p&gt;Después de poner en práctica las tres leyes cumplimos el ciclo del TDD, pero antes de empezar un nuevo ciclo lo que debemos hacer si corresponde es refactorizar el código, hacerlo más corto, más sencillo o lo que corresponda en cada caso. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La refactorización del anterior código no debe modificar el comportamiento del código&lt;/strong&gt;, solo debe modificar el código en sí, y debería de pasar todas las anteriores pruebas.&lt;/p&gt;

&lt;p&gt;En este breve ejemplo podemos observar dos cosas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hemos testeado que nuestro código falla.&lt;/li&gt;
&lt;li&gt;Hemos testeado que nuestro código funciona.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos dos conceptos son importantes porque por lo general, nosotros, los programadores, casi siempre testeamos código para que funcione, en este caso obligamos a que falle para después arreglar el fallo y así asegurarnos que no falla.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Cómo Funciona En La Práctica
&lt;/h1&gt;

&lt;p&gt;Vamos a ver el ejemplo anterior de manera práctica y en varios ciclos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ciclo Uno
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Creamos el test que falla
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Test clase persona&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;En este caso uso Javascript y hay que tener en cuenta que si importas un modulo que no se exporte, el test no falla, por lo tanto vamos a escribir un poco mas de código de test para que falle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;person.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./person.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person Suite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create Person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Si ejecutamos el test mediante &lt;code&gt;jest&lt;/code&gt; veremos que falla, estamos importando un módulo que no existe &lt;em&gt;(esto no falla)&lt;/em&gt; y estamos intentando instanciar una clase que no existe, aquí es donde falla.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Añadimos código mínimo de producción para arreglar el fallo
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Creamos clase persona&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;person.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Con este cambio, el test ya pasa y sabemos que nuestra última versión de código funciona.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Fin del ciclo &lt;em&gt;(refactorizar código)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;De momento no hay nada que refactorizar, así que volvemos a empezar el ciclo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ciclo Dos
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Creamos el test que falla
&lt;/h3&gt;

&lt;p&gt;Ahora quiero añadir un nombre al objeto persona, así que voy a escribir un test que me permita añadir el nombre utilizando un método de la clase &lt;em&gt;(que aún no existe)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;person.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should set person name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Al ejecutar la suite de tests, el primer test sigue pasando, pero el nuevo no pasa, no existe el método &lt;code&gt;setName&lt;/code&gt;. Por lo tanto vamos a arreglar el código de producción para que pase este test.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Añadimos código de producción para arreglar el fallo
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;person.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Con este sencillo cambio todos nuestros tests pasan y estamos seguros que nuestra última versión de código funciona correctamente.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Fin del ciclo &lt;em&gt;(refactorizar código)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;En este paso podríamos refactorizar guardando el nombre en un atributo de la clase por ejemplo, pero vamos a evitar saltar pasos y vamos a otro ciclo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ciclo Tres
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Test qué falla
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Obtener el nombre de la persona&lt;/em&gt;&lt;br&gt;
&lt;code&gt;person.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should get the name of person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Arreglar fallo
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;person.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ahora el test pasa y sabemos que la última versión de nuestro código funciona correctamente.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ciclo Cuatro
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Test qué falla
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;person.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should get the assigned name of person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;// Parte en la que falla&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Arreglar el fallo
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;person.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Y de esta manera podemos ir progresando en el desarrollo de la clase persona hasta complicarla lo máximo posible y sabiendo siempre que la última versión de nuestro código funciona.&lt;/p&gt;

&lt;p&gt;También estaremos obligados de manera implícita a escribir código correcto, el tdd nos obliga a ello.&lt;/p&gt;
&lt;h1&gt;
  
  
  Referencias
&lt;/h1&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://anayamultimedia.es/libro/titulos-especiales/la-artesania-del-codigo-limpio-robert-c-martin-9788441544994/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fanayamultimedia.es%2F%2Fimagenes%2Flibros%2F9788441544994-la-artesania-del-codigo-limpio.jpg" height="257" class="m-0" width="200"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://anayamultimedia.es/libro/titulos-especiales/la-artesania-del-codigo-limpio-robert-c-martin-9788441544994/" rel="noopener noreferrer" class="c-link"&gt;
          La artesanía del código limpio - Anaya Multimedia 
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Anaya Multimedia , Cómo escribir código del que se sienta orgulloso... todos los días

En \'La artesanía del código limpio\' el legendario Robert C
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanayamultimedia.es%2Fimagenes%2Ffavicon.png" width="32" height="32"&gt;
        anayamultimedia.es
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>testing</category>
      <category>javascript</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>Inyección de Dependencias en Android (skel) 💉</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Thu, 01 Jun 2023 07:56:12 +0000</pubDate>
      <link>https://dev.to/dragosb/inyeccion-de-dependencias-en-android-skel-7j</link>
      <guid>https://dev.to/dragosb/inyeccion-de-dependencias-en-android-skel-7j</guid>
      <description>&lt;p&gt;La principal idea de dicho post es tener un esqueleto básico de la Inyección de Dependencias en Android mediante Dagger Hilt. &lt;/p&gt;

&lt;p&gt;Por lo tanto, obviaré explicaciones sobre dicho patrón y que problemas resuelve. &lt;/p&gt;

&lt;p&gt;Adjunto un enlace de una publicación de &lt;code&gt;freeCodeCamp&lt;/code&gt; en la que se explica: &lt;a href="https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/" rel="noopener noreferrer"&gt;Dependency Injection: what it is&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencias Dagger Hilt&lt;/li&gt;
&lt;li&gt;Clase Application&lt;/li&gt;
&lt;li&gt;Proporcionar las dependencias&lt;/li&gt;
&lt;li&gt;Inyección en constructor&lt;/li&gt;
&lt;li&gt;Inyección en atributos&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Módulos&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proveer dependencias en módulos&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Testing de la Inyección de Dependencias&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencias Testing&lt;/li&gt;
&lt;li&gt;testInstrumentationRunner&lt;/li&gt;
&lt;li&gt;CustomRunner&lt;/li&gt;
&lt;li&gt;Clase de Test&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h1&gt;
  
  
  Dependencias Dagger Hilt
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419#setup" rel="noopener noreferrer"&gt;Documentación Oficial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;project/build.gradle&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger.hilt.android'&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'2.44'&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;project/app/build.gradle&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;  
&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-kapt'&lt;/span&gt;  
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger.hilt.android'&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;  

&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"com.google.dagger:hilt-android:2.44"&lt;/span&gt;  
    &lt;span class="n"&gt;kapt&lt;/span&gt; &lt;span class="s2"&gt;"com.google.dagger:hilt-compiler:2.44"&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;  

&lt;span class="n"&gt;kapt&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;correctErrorTypes&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Clase Application
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419#application-class" rel="noopener noreferrer"&gt;Documentación Oficial&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Obligatoria&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltAndroidApp&lt;/span&gt;  
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Propiedad nombre (&lt;code&gt;AndroidManifest.xml&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".BaseApp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Proporcionar las dependencias
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419#android-classes" rel="noopener noreferrer"&gt;Documentación Oficial&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltViewModel&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h1&gt;
  
  
  Inyección en constructor
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;(mejor)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419#define-bindings" rel="noopener noreferrer"&gt;Documentación Oficial&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltViewModel&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomViewModel&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt;
&lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;myRepo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Inyección en atributos
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;(peor)&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltViewModel&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;myRepo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;

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

&lt;/div&gt;






&lt;h1&gt;
  
  
  Módulos
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419#hilt-modules" rel="noopener noreferrer"&gt;Documentación Oficial&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Module&lt;/span&gt;  
&lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SingletonComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="c1"&gt;// Funciones para proveer clases&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Opciones &lt;code&gt;@InstallIn&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Proveer dependencias en módulos
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Singleton&lt;/span&gt;  
&lt;span class="nd"&gt;@Provides&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;providesDatabase&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;databaseBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nc"&gt;UsersDb&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"users_db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Provides&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;provideApplicationContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Testing de la Inyección de Dependencias
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;(androidTests/)&lt;/em&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Importar dependencias&lt;/li&gt;
&lt;li&gt;Cambiar el &lt;code&gt;testInstrumentationRunner&lt;/code&gt; en &lt;code&gt;app/build.gradle&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Crear un &lt;code&gt;CustomRunner&lt;/code&gt; de testing utilizando la clase &lt;code&gt;HiltTestApplication&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Anotar la clase de test con &lt;code&gt;@HiltAndroidTest&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Dependencias Testing
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;app/build.gradle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;testImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger:hilt-android-testing:2.44'&lt;/span&gt;  
    &lt;span class="n"&gt;kaptTest&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger:hilt-android-compiler:2.44'&lt;/span&gt;  
    &lt;span class="n"&gt;androidTestImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger:hilt-android-testing:2.44'&lt;/span&gt;  
    &lt;span class="n"&gt;kaptAndroidTest&lt;/span&gt; &lt;span class="s1"&gt;'com.google.dagger:hilt-android-compiler:2.44'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  testInstrumentationRunner
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;app/build.gradle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;testInstrumentationRunner&lt;/span&gt; &lt;span class="s2"&gt;"com.package.name.CustomRunner"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CustomRunner
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomRunner&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AndroidJUnitRunner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;newApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="n"&gt;cl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClassLoader&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;  
        &lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;  
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HiltTestApplication&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Clase de Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltAndroidTest&lt;/span&gt;
&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidJUnit4&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DITests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="c1"&gt;// Es la clase que inyecta dependencias en los tests&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;Rule&lt;/span&gt;  
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;hiltRule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HiltAndroidRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="c1"&gt;// Inyección (pero no se inyecta)&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;  
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;  

    &lt;span class="c1"&gt;// Aqui es donde se inyecta&lt;/span&gt;
    &lt;span class="nd"&gt;@Before&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;hiltRule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Test&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;testContextInjection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cacheDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cacheDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;  
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cacheDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cache"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>android</category>
      <category>kotlin</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Testing en Android</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Mon, 22 May 2023 14:27:21 +0000</pubDate>
      <link>https://dev.to/dragosb/testing-en-android-3pe5</link>
      <guid>https://dev.to/dragosb/testing-en-android-3pe5</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Tipos de Tests&lt;/li&gt;
&lt;li&gt;
Directorios del proyecto

&lt;ul&gt;
&lt;li&gt;Directorio &lt;code&gt;tests&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Directorio &lt;code&gt;androidTests&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Ejemplos

&lt;ul&gt;
&lt;li&gt;Test unitarios&lt;/li&gt;
&lt;li&gt;Test de integración&lt;/li&gt;
&lt;li&gt;Test de IU&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Tipos de Tests
&lt;/h1&gt;

&lt;p&gt;Los tres tipos de tests que se realizan en Android &lt;em&gt;(en general en cualquier lenguaje/framework son iguales)&lt;/em&gt; son los siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt;: tests por unidad, es decir testear las clases o funciones de forma individual y verificar que cada una haga lo que se supone que debe hacer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Tests&lt;/strong&gt;: tests que validan la integración entre diferentes módulos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Tests&lt;/strong&gt;: tests de la interfaz del usuario, o end to end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SNmT1auq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/de7026u8o87odnxfmlc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SNmT1auq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/de7026u8o87odnxfmlc8.png" alt="Pirámide testing" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google recomienda dividir los tipos de tests de la siguiente forma:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tipo Test&lt;/th&gt;
&lt;th&gt;Porcentaje&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unit tests&lt;/td&gt;
&lt;td&gt;70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration Test&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI Tests&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Directorios del proyecto
&lt;/h1&gt;

&lt;p&gt;Existen dos formas de ejecutar los tests en Android:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En la maquina local, mediante la JVM.&lt;/li&gt;
&lt;li&gt;En un dispositivo real &lt;em&gt;(o emulado)&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dependiendo de donde se quieran ejecutar las pruebas &lt;em&gt;(en local o real)&lt;/em&gt; existen dos directorios en el proyecto:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;com/example/project/tests/&lt;/code&gt;: &lt;strong&gt;local&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;com/example/project/androidTests/&lt;/code&gt;: &lt;strong&gt;real&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Directorio tests
&lt;/h2&gt;

&lt;p&gt;En dicho directorio se guardaran todos los &lt;strong&gt;test&lt;/strong&gt; relacionados con la &lt;strong&gt;ejecución&lt;/strong&gt; en la &lt;strong&gt;maquina local&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por lo general serán los &lt;strong&gt;tests unitarios&lt;/strong&gt; los que se guarden en dicho directorio porque no acceden a recursos del dispositivo y tampoco tienen que interactuar con el dispositivo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Directorio androidTests
&lt;/h2&gt;

&lt;p&gt;En este directorio se guardaran todos los &lt;strong&gt;tests&lt;/strong&gt; que se vayan a &lt;strong&gt;ejecutar&lt;/strong&gt; en el &lt;strong&gt;dispositivo&lt;/strong&gt; real  o en un &lt;strong&gt;emulador&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Los tipos de tests que se guardarán en dicho directorios son &lt;strong&gt;tests de integración&lt;/strong&gt; y &lt;strong&gt;e2e&lt;/strong&gt; &lt;em&gt;(end-to-end)&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ejemplos
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;En los ejemplos siguientes, no muestro como añadir las dependencias necesarias para los tests y tampoco menciono que dependencias son necesarias. Consultar la guía oficial en las referencias para ver la implementación completa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Test unitarios
&lt;/h2&gt;

&lt;p&gt;Estos tipos de tests a mi parecer son los mas sencillos de entender, ya que pruebas cosas de forma individual, funciones o métodos de clases.&lt;/p&gt;

&lt;p&gt;Imagina que vamos a querer comprobar dos métodos de la clase &lt;code&gt;MyFunctions&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El primer método se encarga de sumar dos números.&lt;/li&gt;
&lt;li&gt;El segundo devuelve la fecha de hoy en formato &lt;code&gt;dd-MM-yyyy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Son dos métodos muy básicos pero útiles para entender las pruebas unitarias&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Clase a testear
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFunctions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getCustomDate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleDateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dd-MM-yyyy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDefault&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Para testear dichas funciones vamos a crear el fichero &lt;code&gt;com.example.project/tests/MyFuncionsTests.kt&lt;/code&gt; y dentro estará la lógica que comprobará que cada función hace lo que debe hacer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Una buena práctica para realizar tests es provocar que la aplicación falle de cualquier manera. Es decir utilizarla de la forma en la que no se había pensado.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si un input está pensado para introducir números, vamos a introducir texto a ver que ocurre. Debemos pensar como un usuario y no como el desarrollador que ha implementado dicha funcionalidad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para realizar los tests utilizamos &lt;code&gt;JUnit&lt;/code&gt; que nos provee de las anotaciones &lt;code&gt;@Before&lt;/code&gt;, &lt;code&gt;@After&lt;/code&gt; y &lt;code&gt;@Test&lt;/code&gt; entre otras.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFunctionsTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;myFunctions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyFunctions&lt;/span&gt;

    &lt;span class="c1"&gt;// Se ejecuta antes de ejecutar cada test&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nd"&gt;@Before&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;myFunctions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyFunctions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/*             Tests            */&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`add&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="nf"&gt;addition`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`add&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;incorrect&lt;/span&gt; &lt;span class="nf"&gt;addition`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;assertNotEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`get&lt;/span&gt; &lt;span class="n"&gt;custom&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="nf"&gt;dd-MM-yyyy`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;fechaEsperada&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleDateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dd-MM-yyyy"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;fechaObtenida&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCustomDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fechaEsperada&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fechaObtenida&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Las anotaciones se utilizan para indicar que es cada método de la clase, ya que si no se indica mediante las anotaciones de JUnit, son simples métodos dentro de una clase.&lt;/p&gt;

&lt;p&gt;Anotaciones comunes de JUnit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Anotacion&lt;/th&gt;
&lt;th&gt;Descripcion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Indica que el método es un Test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Before&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;El método se ejecutará antes de &lt;strong&gt;cada&lt;/strong&gt; test. Si hay 3 tests se ejecuta 3 veces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@After&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Igual que &lt;code&gt;@Before&lt;/code&gt; pero después de cada test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@BeforeClass&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Se ejecutará dicho método una vez antes de ejecutar los tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@AfterClass&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Se ejecutará el método al finalizar la ejecución de todos los tests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Existen mas anotaciones pero las básicas son las de la tabla. &lt;/p&gt;

&lt;p&gt;Un punto importante es que las anotaciones &lt;code&gt;BeforeClass&lt;/code&gt; y &lt;code&gt;AfterClass&lt;/code&gt; deben anotar a métodos estáticos y públicos; en &lt;strong&gt;java&lt;/strong&gt; con poner el método como &lt;code&gt;public static&lt;/code&gt; funciona, en &lt;strong&gt;kotlin&lt;/strong&gt; el método debe estar dentro de un &lt;code&gt;companion object&lt;/code&gt; &lt;em&gt;(para que sea static)&lt;/em&gt; y utilizar la anotación &lt;code&gt;@JvmStatic&lt;/code&gt; aparte de &lt;code&gt;@BeforeClass&lt;/code&gt; o &lt;code&gt;@AfterClass&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se puede observar que los nombres de las funciones en los tests pueden ir nombradas entre comillas inversas y con espacios en blanco, para que quede mas entendible.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El primer test utiliza la función &lt;code&gt;add&lt;/code&gt; con dos parámetros a sumar y verifica que el resultado de la suma es el esperado.&lt;/li&gt;
&lt;li&gt;El segundo, verifica la misma función pero que el resultado a comprobar no coincida con el esperado.&lt;/li&gt;
&lt;li&gt;El ultimo verifica que la fecha devuelta por la función &lt;code&gt;getCustomDate&lt;/code&gt; es igual que nuestro resultado esperado.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Test de integración
&lt;/h2&gt;

&lt;p&gt;Los tests de integración en la teoría parecen sencillos de entender, pero a mi, en la practica me han resultado mas complejos, ya que no me quedaba claro cuando se pasaba de pruebas unitarias a pruebas de integración.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si vamos a verificar que un &lt;strong&gt;ViewModel&lt;/strong&gt; interactúa adecuadamente con una &lt;strong&gt;base de datos&lt;/strong&gt; (como Room) o con una &lt;strong&gt;API&lt;/strong&gt;, estaríamos realizando un test de integración.&lt;/p&gt;

&lt;p&gt;Del mismo modo, si el &lt;strong&gt;ViewModel&lt;/strong&gt; interactúa con un &lt;strong&gt;repositorio&lt;/strong&gt; &lt;em&gt;(patron repository)&lt;/em&gt;, y este repositorio a su vez se comunica con un &lt;strong&gt;DataStore&lt;/strong&gt;, este escenario también seria un test de integración.&lt;/p&gt;

&lt;p&gt;Pongamos el caso de testear la integración entre &lt;strong&gt;ViewModel &amp;lt;--&amp;gt; API&lt;/strong&gt;, en esta prueba, lo que se pretende &lt;strong&gt;verificar&lt;/strong&gt; es el &lt;strong&gt;funcionamiento&lt;/strong&gt; entre los &lt;strong&gt;dos componentes&lt;/strong&gt;. Es decir que el test seguirá siendo de integración si accedemos a los datos reales de la API o utilizamos un Mock.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Si accedemos a los datos reales de la API estamos testeando la integración real.&lt;/li&gt;
&lt;li&gt;Si utilizamos un Mock para la API, estamos testeando como el ViewModel maneja los datos recibidos desde la API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Otro ejemplo podría ser probar la clase que interactúa con la API. Si dicha clase utiliza el patrón Repository lo que vamos a testear es el repositorio de la API, entonces seria un test de integración ya que se verifica nuestro código con un componente externo. En cambio, si vamos a querer testear la lógica interna del repositorio, podríamos mockear los datos y esto pasaría a ser un test unitario.&lt;/p&gt;

&lt;p&gt;En este ejemplo tenemos lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Acceso a &lt;strong&gt;base de datos&lt;/strong&gt; (Room).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El objeto que configura la base de datos.&lt;/li&gt;
&lt;li&gt;El obtejo entity (referente a la tabla)&lt;/li&gt;
&lt;li&gt;El DAO &lt;em&gt;(Data Access Objetc)&lt;/em&gt; las consultas &lt;code&gt;sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;La implementación al acceso a datos mediante el patrón Repository

&lt;ul&gt;
&lt;li&gt;Un interface &lt;em&gt;(repository)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;La implementación del interface &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El &lt;strong&gt;ViewModel&lt;/strong&gt; que utiliza el Repository para acceder a los datos.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dWrBini8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi40g8wfksu5ykcrpd0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dWrBini8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi40g8wfksu5ykcrpd0k.png" alt="Diagrama de test de integracion" width="784" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y lo que vamos a testear es la integración entre el &lt;strong&gt;ViewModel&lt;/strong&gt; y la &lt;strong&gt;Base de Datos&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  ViewModel
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@HiltViewModel&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserViewModel&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt;  
&lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*Inyeccion Dependencias*/&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableStateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_user&lt;/span&gt;  

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

        &lt;span class="c1"&gt;// Ejecutamos una corutina en el scope del ViewModel&lt;/span&gt;
        &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

            &lt;span class="c1"&gt;// Utilizamos el método getUser del Repository&lt;/span&gt;
            &lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  
                &lt;span class="n"&gt;_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;  

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

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  

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

&lt;/div&gt;

&lt;h4&gt;
  
  
  Acceso a datos
&lt;/h4&gt;
&lt;h5&gt;
  
  
  DB
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;La definición de la base de datos, especificando la tabla (entity) y las consultas (el DAO como abstract fun)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RoomDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;usersDao&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;UserDao&lt;/span&gt;  

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;  
        &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
                &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;  
                    &lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;databaseBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"users_db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
            &lt;span class="p"&gt;}&lt;/span&gt;  

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  Entity (tabla)
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;La tabla con su schema&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="nd"&gt;@ColumnInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="nd"&gt;@ColumnInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  DAO
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Las consultas a la base de datos&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Dao&lt;/span&gt;  
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserDao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM users WHERE id = :id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  

    &lt;span class="nd"&gt;@Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OnConflictStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Implementación acceso a datos
&lt;/h4&gt;
&lt;h5&gt;
  
  
  Repository
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Declaración de los métodos&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  Repository Implementation
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserDao&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="c1"&gt;// Definición de los métodos&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Por no añadir más código y hacer la explicación las complicada he optado por omitir la Inyección de Dependencias. Saber que la realizo con Dagger Hilt y proveo las clases &lt;code&gt;UsersDb&lt;/code&gt;, &lt;code&gt;UserDao&lt;/code&gt; y &lt;code&gt;UserImpl&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Tests
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserViewModelTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserDao&lt;/span&gt;  
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;  

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserViewModel&lt;/span&gt;  

    &lt;span class="nd"&gt;@Before&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;// Contexto de la app en modo Test  &lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InstrumentationRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstrumentation&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;  

        &lt;span class="c1"&gt;// Creamos la BBDD ficticia en RAM  &lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inMemoryDatabaseBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UsersDb&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;userDao&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;usersDao&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="n"&gt;userRepository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="n"&gt;viewModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"alice@mail.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@After&lt;/span&gt; 
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Este metodo se ejcutará después de cada test&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Test&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;shouldViewModelSaveUserInDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;runBlocking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;// Al ser un metodo 'suspend' debemos utilizar 'runBlocking' para ejecutar la corutina y  &lt;/span&gt;
        &lt;span class="c1"&gt;// bloquear el hilo.  &lt;/span&gt;

        &lt;span class="c1"&gt;// El ViewModel guarda el usuario        &lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="c1"&gt;// Obtenemos usuario con id: 1&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;savedUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

        &lt;span class="c1"&gt;// Verificamos que el usuario es el mismo que el de la base de datos.  &lt;/span&gt;
        &lt;span class="c1"&gt;// Si es el mismo, el viewmodel ha funcionado correctamente a la hora        &lt;/span&gt;
        &lt;span class="c1"&gt;// de guardar el usuario en bbdd.        &lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Test&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nf"&gt;runBlocking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Probamos a guardar un usuario desde el ViewModel&lt;/span&gt;
            &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

            &lt;span class="c1"&gt;// Obtenemos un usuario con id: 1&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userFromDb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

            &lt;span class="c1"&gt;// Verificamos que los usuarios son iguales&lt;/span&gt;
            &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFromDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Test de IU
&lt;/h2&gt;

&lt;p&gt;En este ejemplo testearé un botón en Jetpack Compose, para realizarlo lo haremos como en el ejemplo.&lt;/p&gt;
&lt;h4&gt;
  
  
  Composable
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;showDialog&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;showDialog&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;showDialog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Click me!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showDialog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saludo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"showDialog"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="nf"&gt;onClickDialog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="p"&gt;}}&lt;/span&gt;  

&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onClickDialog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nc"&gt;Dialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onDismissRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/*TODO*/&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Dialogo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Test
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingComposableTesting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"TEST"&lt;/span&gt;  

    &lt;span class="c1"&gt;// Creamos una regla de JUnit para un Composable&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;Rule&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createComposeRule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;// A la regla le añadimos el composable a testear&lt;/span&gt;
        &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Test&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;buttonExists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="c1"&gt;// Comprobamos que el nodo con el texto "Click me!" existe.  &lt;/span&gt;
        &lt;span class="n"&gt;rule&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNodeWithText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Click me!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No existe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;clickButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;rule&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNodeWithText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Click me!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="c1"&gt;// Verificamos que el nodo es clickable&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertHasClickAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
            &lt;span class="c1"&gt;// Hacemos click en el botón&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;performClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

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

&lt;/div&gt;


&lt;p&gt;Adjunto cheatsheet de testing en Jetpack Compose:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sKOM07Dx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zeogn0kk82pa8dfkvvb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sKOM07Dx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zeogn0kk82pa8dfkvvb5.png" alt="Jetpack Compose testing cheatsheet" width="800" height="1132"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Referencias
&lt;/h1&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/training/testing?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vhTs4lON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/social/android-developers.png%3Fhl%3Des-419" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/training/testing?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Cómo probar apps en Android  |  Desarrolladores de Android  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/training/testing/fundamentals?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vhTs4lON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/social/android-developers.png%3Fhl%3Des-419" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/training/testing/fundamentals?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Aspectos básicos de las pruebas  |  Desarrolladores de Android  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/testing?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zZvuJirK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/jetpack/compose/testing-semantic-tree.png%3Fhl%3Des-419" height="699" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/testing?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Cómo probar tu diseño de Compose  |  Jetpack Compose  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>android</category>
      <category>testing</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Servicios en Android🛸</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Wed, 19 Apr 2023 11:30:09 +0000</pubDate>
      <link>https://dev.to/dragosb/servicios-en-android-1g9j</link>
      <guid>https://dev.to/dragosb/servicios-en-android-1g9j</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Definición&lt;/li&gt;
&lt;li&gt;Diferencias&lt;/li&gt;
&lt;li&gt;
Para que se usan

&lt;ul&gt;
&lt;li&gt;Background&lt;/li&gt;
&lt;li&gt;Foreground&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Implementación

&lt;ul&gt;
&lt;li&gt;Background Services&lt;/li&gt;
&lt;li&gt;Foreground Services&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Tareas Programadas&lt;/li&gt;
&lt;li&gt;Referencias&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Definición
&lt;/h1&gt;

&lt;p&gt;Un &lt;strong&gt;servicio&lt;/strong&gt; en &lt;strong&gt;Android&lt;/strong&gt; se asemeja a un &lt;strong&gt;demonio&lt;/strong&gt; en sistemas &lt;strong&gt;GNU/Linux&lt;/strong&gt;, es decir que es un &lt;strong&gt;programa&lt;/strong&gt; en ejecución en &lt;strong&gt;segundo plano&lt;/strong&gt; sin necesidad de interactuar con el usuario. Por lo tanto un servicio no tiene interfaz gráfica.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El termino 'segundo plano' en el contexto de servicios en android puede crear confusión ya que existen los servicios en segundo plano (background) y los servicios en primer plano (foreground).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La &lt;strong&gt;creación&lt;/strong&gt; y &lt;strong&gt;ejecución&lt;/strong&gt; de un servicio en Android &lt;strong&gt;no es&lt;/strong&gt; como en un sistema &lt;strong&gt;GNU/Linux&lt;/strong&gt; &lt;em&gt;(que creas un fichero con la configuración para &lt;code&gt;systemd&lt;/code&gt; y utilizando &lt;code&gt;systemctl&lt;/code&gt; lo pones en ejecución)&lt;/em&gt; en este caso el servicio siempre lo deberá &lt;strong&gt;ejecutar&lt;/strong&gt; la &lt;strong&gt;aplicación principal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5szv_KJk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1fo13p8jkd5kewh9hnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5szv_KJk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1fo13p8jkd5kewh9hnf.png" alt="Flow de ejecucion de los servicios en android (background services/foreground services)" width="574" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En &lt;strong&gt;Android&lt;/strong&gt; existen &lt;strong&gt;dos tipos&lt;/strong&gt; de servicios, los &lt;strong&gt;Background Services&lt;/strong&gt; y los &lt;strong&gt;Foreground Services&lt;/strong&gt;. Los dos son muy parecidos pero tiene diferencias notables.&lt;/p&gt;




&lt;h1&gt;
  
  
  Diferencias
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Background Services&lt;/th&gt;
&lt;th&gt;Foreground Services&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; es necesario &lt;strong&gt;notificar&lt;/strong&gt; al usuario de su ejecución&lt;/td&gt;
&lt;td&gt;Es &lt;strong&gt;obligatorio&lt;/strong&gt; mostrar una &lt;strong&gt;notificación&lt;/strong&gt; al usuario (parte superior)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tienen &lt;strong&gt;baja prioridad&lt;/strong&gt; para el SO&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Alta prioridad&lt;/strong&gt; para el SO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;El SO lo &lt;strong&gt;puede parar&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;El SO &lt;strong&gt;no lo suele parar&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consume &lt;strong&gt;menos&lt;/strong&gt; &lt;strong&gt;recursos&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Consume &lt;strong&gt;más&lt;/strong&gt; &lt;strong&gt;recursos&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Tiempo&lt;/strong&gt; de vida &lt;strong&gt;corto&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Tiempo&lt;/strong&gt; de vida &lt;strong&gt;largo&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; &lt;strong&gt;afectan&lt;/strong&gt; la &lt;strong&gt;experiencia&lt;/strong&gt; del usuario&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Afectan&lt;/strong&gt; la &lt;strong&gt;experiencia&lt;/strong&gt; del usuario&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  Para que se usan
&lt;/h1&gt;

&lt;p&gt;Un servicio se puede utilizar para cosas que no tenga que intervenir el usuario y que sea transparente para el. También se puede utilizar para ejecutar funcionalidades en segundo plano con una interacción con el usuario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Son útiles para tareas que no requieren interacción con el usuario y pueden ejecutarse sin su intervención.&lt;/p&gt;

&lt;p&gt;Como casos de uso pueden ser la sincronización de datos, copias de seguridad automáticas y actualización de bases de datos. &lt;/p&gt;

&lt;p&gt;Evitar realizar tareas de larga duración ya que el sistema lo puede parar cuando lo vea necesario&lt;/p&gt;

&lt;h2&gt;
  
  
  Foreground
&lt;/h2&gt;

&lt;p&gt;Al tener que mostrar una notificación permanente cuando se encuentra en ejecución un servicio como este, algunos ejemplos de uso pueden ser:   la &lt;strong&gt;reproducción&lt;/strong&gt; de &lt;strong&gt;música&lt;/strong&gt;, al usuario se le informa mediante una notificación de que se reproduce música, &lt;strong&gt;permitiendo&lt;/strong&gt; &lt;strong&gt;interactuar&lt;/strong&gt; con el reproductor parando, pausando, avanzando, retrocediendo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1bC1ZpKJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tz0e84ijkcs9nra4wd7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1bC1ZpKJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tz0e84ijkcs9nra4wd7c.png" alt="Notificacion de un Foreground service en Android " width="481" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;También se puede utilizar para &lt;strong&gt;descargas&lt;/strong&gt; de &lt;strong&gt;ficheros&lt;/strong&gt; de gran tamaño, donde se muestra al usuario el &lt;strong&gt;progreso&lt;/strong&gt; de la &lt;strong&gt;descarga&lt;/strong&gt; y también se permite la pausa o la cancelación de la misma. &lt;em&gt;(Por ejemplo cuando una aplicación se actualiza, se muestra una notificación de este estilo)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Otro uso que se le puede dar es el &lt;strong&gt;seguimiento&lt;/strong&gt; del usuario mediante &lt;strong&gt;GPS&lt;/strong&gt; e informándole que se están capturando los datos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En una ocasión he utilizado este tipo de servicio para grabar Audio y Video en segundo plano.&lt;/p&gt;

&lt;p&gt;El Audio lo grababa mediante &lt;a href="https://developer.android.com/guide/topics/media/mediarecorder?hl=es-419"&gt;&lt;code&gt;MediaRecorder&lt;/code&gt;&lt;/a&gt; y video mediante &lt;a href="https://developer.android.com/training/camerax?hl=es-419"&gt;&lt;code&gt;CameraX&lt;/code&gt;&lt;/a&gt;, la implementación que realicé fue un &lt;code&gt;Foreground Service&lt;/code&gt; ya que &lt;code&gt;MediaRecorder&lt;/code&gt; a partir del API 28 no permite el acceso al micrófono desde un &lt;code&gt;Background Service&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cuando ocurría determinado evento, otro servicio ejecutaba este servicio (el de grabación) y comenzaba a grabar. Era obligatorio mostrar una notificación al usuario de que estaba siendo grabado.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Implementación
&lt;/h1&gt;

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

&lt;p&gt;Ejemplo de como crear un Background Service que se ejecuta desde un Composable&lt;/p&gt;

&lt;h3&gt;
  
  
  Servicio
&lt;/h3&gt;

&lt;p&gt;Heredar de &lt;code&gt;Service&lt;/code&gt; y sobrescribir los métodos &lt;code&gt;onBind&lt;/code&gt;, &lt;code&gt;onStartCommand&lt;/code&gt; y &lt;code&gt;onDestroy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;En el método &lt;code&gt;onStartCommand&lt;/code&gt; si queremos que el servicio se ejecute si se cierra la aplicación retornar la constante &lt;code&gt;START_STICKY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBackgroundService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;IBinder&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onStartCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Tarea que va a realizar el servicio&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;START_STICKY&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  El Composable
&lt;/h3&gt;

&lt;p&gt;El composable es un botón que recibe dos funciones por parámetro, para  iniciar el servicio y para parar el servicio. &lt;/p&gt;

&lt;p&gt;Estas funciones en este caso están creadas en la clase &lt;code&gt;main&lt;/code&gt;, lo ideal es tenerlas creadas en un &lt;code&gt;ViewModel&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;StartStopServiceButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;onStartService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;onStopService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;isServiceRunning&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;isServiceRunning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isServiceRunning&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isServiceRunning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onStartService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onStopService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isServiceRunning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"Detener Servicio"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"Iniciar Servicio"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Fichero &lt;code&gt;manifest&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Hay que declarar el servicio en el manifest del proyecto.&lt;/p&gt;

&lt;p&gt;Exported es para permitir o no que otra aplicación pueda ejecutar el servicio.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
        &lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
            &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MyBackgroundService"&lt;/span&gt;
            &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Main Activity
&lt;/h3&gt;

&lt;p&gt;La clase &lt;code&gt;main&lt;/code&gt; consta de dos funciones , una para ejecutar el servicio y otra para parar el servicio.&lt;/p&gt;

&lt;p&gt;También muestra el botón y pasa las funciones por parámetro al composable.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;MaterialTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Surface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Boton&lt;/span&gt;
                    &lt;span class="nc"&gt;StartStopServiceButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;onStartService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="nf"&gt;startMyBackgroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
                        &lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="n"&gt;onStopService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="nf"&gt;stopMyBackgroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
                        &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;startMyBackgroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nc"&gt;MyBackgroundService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;stopMyBackgroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nc"&gt;MyBackgroundService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;stopService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Foreground Services
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Servicio
&lt;/h3&gt;

&lt;p&gt;La declaracion de un &lt;strong&gt;foreground&lt;/strong&gt; service es muy &lt;strong&gt;similar&lt;/strong&gt; al &lt;strong&gt;background&lt;/strong&gt; service, lo unico que &lt;strong&gt;cambia&lt;/strong&gt; es lo &lt;strong&gt;siguiente&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crear la &lt;strong&gt;notificación&lt;/strong&gt; para mostrar al usuario&lt;/li&gt;
&lt;li&gt;En el método &lt;code&gt;onStartCommand&lt;/code&gt; hay que &lt;strong&gt;ejecutar&lt;/strong&gt; el método &lt;strong&gt;&lt;code&gt;startForeground&lt;/code&gt;&lt;/strong&gt; con la notificación creada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para versiones iguales o superiores a Android 8 (API 26) hay que crear el canal para la notificación como en el método &lt;code&gt;createNotificationChannel()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La notificación se crea mediante &lt;code&gt;NotificationCompat.Builder&lt;/code&gt; en el método &lt;code&gt;createNotification()&lt;/code&gt;, dicho método retorna una &lt;code&gt;Notification&lt;/code&gt; que la recibirá el método &lt;code&gt;startForeground()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyForegroundService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CHANNEL_ID&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my_channel_id"&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;NOTIFICATION_ID&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onStartCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; 
            &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;startId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notification&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nf"&gt;startForeground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NOTIFICATION_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;START_NOT_STICKY&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;IBinder&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Crea el canal para la notificación&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;CHANNEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"My Foreground Service Channel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IMPORTANCE_DEFAULT&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notificationManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
             &lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotificationManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;notificationManager&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Crea la notifcación&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;NotificationCompat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CHANNEL_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Foreground Service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Servicio en primer plano..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSmallIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ic_notification_icon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Composable
&lt;/h3&gt;

&lt;p&gt;El composable recibe por parámetro una función que al hacer click en el botón se ejecuta dicha función.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onStartService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;onStartService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Iniciar Foreground Service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Fichero &lt;code&gt;manifest&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Para versiones iguales o superiores a la &lt;strong&gt;API 28&lt;/strong&gt; hay que añadir el permiso &lt;code&gt;FOREGROUND_SERVICE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cada servicio se declara dentro de &lt;code&gt;application&lt;/code&gt; mediante la etiqueta &lt;a href="https://developer.android.com/guide/topics/manifest/service-element?hl=es-419"&gt;&lt;code&gt;service&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.FOREGROUND_SERVICE"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
            &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MyForegroundService"&lt;/span&gt;
            &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
            &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        ...

    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Main Activity
&lt;/h3&gt;

&lt;p&gt;La clase &lt;code&gt;main&lt;/code&gt; se encarga de mostrar el botón y vincular el método privado que inicia el servicio, muy parecido en el anterior ejemplo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;MyButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;onStartService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;startMyForegroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;startMyForegroundService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyForegroundService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Tareas Programadas
&lt;/h1&gt;

&lt;p&gt;Si necesitas gestionar &lt;strong&gt;notificaciones&lt;/strong&gt;, como un &lt;strong&gt;aviso programado&lt;/strong&gt; en una fecha específica, lo ideal es utilizar un &lt;strong&gt;&lt;a href="https://developer.android.com/topic/libraries/architecture/workmanager?hl=es-419"&gt;&lt;code&gt;WorkManager&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; en lugar de los servicios. Dicha funcionalidad solo está disponible para &lt;strong&gt;Android Jetpack&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Referencias
&lt;/h1&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/guide/components/services?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vhTs4lON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/social/android-developers.png%3Fhl%3Des-419" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/guide/components/services?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Descripción general de los servicios  |  Desarrolladores de Android  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/reference/android/app/Service#constants_1" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--UivXGBqs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/social/android-developers.png" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/reference/android/app/Service#constants_1" rel="noopener noreferrer" class="c-link"&gt;
          Service  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/guide/components/foreground-services#request-foreground-service-permissions" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--UivXGBqs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/social/android-developers.png" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/guide/components/foreground-services#request-foreground-service-permissions" rel="noopener noreferrer" class="c-link"&gt;
          Foreground services  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>android</category>
      <category>kotlin</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Context en Android</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Thu, 13 Apr 2023 17:59:04 +0000</pubDate>
      <link>https://dev.to/dragosb/context-en-android-39lo</link>
      <guid>https://dev.to/dragosb/context-en-android-39lo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuipxe1qv7pxc04pyvjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuipxe1qv7pxc04pyvjf.png" alt="Context en Android infografia resumen" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Indice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Definición&lt;/li&gt;
&lt;li&gt;Como obtener el context&lt;/li&gt;
&lt;li&gt;
Uso

&lt;ul&gt;
&lt;li&gt;Iniciar Activity&lt;/li&gt;
&lt;li&gt;Inicir Servicios&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Utilizarlo en Composables&lt;/li&gt;

&lt;li&gt;Utilizarlo en ViewModels&lt;/li&gt;

&lt;li&gt;Referencias&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Definición
&lt;/h2&gt;

&lt;p&gt;Es una clase abstracta que la implementa Android, y cuya función es proporcionar acceso al entorno de la aplicación.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Así se define en la documentación oficial pero en mi caso no entiendo a que se refiere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si tenemos acceso al entorno de la aplicación, vamos a tener acceso a las siguientes funciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acceder a una base de datos&lt;/li&gt;
&lt;li&gt;Al sistema de notificaciones&lt;/li&gt;
&lt;li&gt;Al sistema de ficheros&lt;/li&gt;
&lt;li&gt;Lanzar actividades, servicios&lt;/li&gt;
&lt;li&gt;Trabajar con permisos&lt;/li&gt;
&lt;li&gt;Mostrar cuadros de diálogo&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Como obtener el Context
&lt;/h2&gt;

&lt;p&gt;La obtención del Context se puede realizar desde varios puntos en una app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desde cualquier &lt;code&gt;Activity&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Desde un &lt;code&gt;Service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Desde cualquier &lt;code&gt;View&lt;/code&gt; &lt;em&gt;(si utilizas el modelo xml)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Desde cualquier &lt;code&gt;Composable&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;O cualquier clase que extienda de &lt;code&gt;Context&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Existen &lt;strong&gt;dos métodos&lt;/strong&gt; para acceder al contexto. Cada uno de ellos &lt;strong&gt;devuelve&lt;/strong&gt; un &lt;strong&gt;contexto diferente&lt;/strong&gt; y las principales diferencias son las siguientes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;code&gt;getContext()&lt;/code&gt; (en views xml)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;getApplicationContext()&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contexto ligado a la Activity&lt;/td&gt;
&lt;td&gt;Contexto ligado a toda la Aplicación&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Depende del ciclo de vida de la Activity&lt;/td&gt;
&lt;td&gt;Depende del ciclo de vida de la Aplicacion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Si muere la activty el context tambien&lt;/td&gt;
&lt;td&gt;Todas las actividades tienen acceso al mismo contexto (aparte del suyo propio)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cada activty tiene el suyo propio&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Usos
&lt;/h2&gt;

&lt;p&gt;A continuación detallaré como se utiliza el context para varias tareas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iniciar Activity
&lt;/h3&gt;

&lt;p&gt;Si vamos a &lt;strong&gt;iniciar una actividad&lt;/strong&gt; diferente a la que se está ejecutando, deberemos hacer uso del &lt;strong&gt;&lt;code&gt;Context&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En el ejemplo accederemos al &lt;strong&gt;context&lt;/strong&gt; desde un &lt;strong&gt;Composable&lt;/strong&gt;, en dicho composable tendremos acceso al &lt;strong&gt;contexto&lt;/strong&gt; de la &lt;strong&gt;activity&lt;/strong&gt; &lt;em&gt;(es decir que dependerá del lifecycle de la activity)&lt;/em&gt; utilizando &lt;code&gt;LocalContext.current&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por ejemplo vamos a querer ejecutar en determinado momento la actvity &lt;code&gt;SecondActivity&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Esta es la segunda actividad"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;La actividad principal, &lt;code&gt;MainActivity&lt;/code&gt; contiene un único &lt;code&gt;Composable&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="nc"&gt;MyComposable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;La  implementación del &lt;code&gt;Composable&lt;/code&gt; que se utiliza en la actividad principal:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyComposable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;  

    &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Iniciar Activity"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;En este ejemplo nuestro composable tiene un &lt;strong&gt;botón&lt;/strong&gt; cuya única función es &lt;strong&gt;obtener el contexto&lt;/strong&gt; y &lt;strong&gt;ejecutar la &lt;code&gt;SecondActivity&lt;/code&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Al ejecutarse accedemos al contexto vinculado a la activity para poder iniciar una segunda actividad en caso de que el usuario pulse el botón.&lt;/p&gt;

&lt;p&gt;Si se ha iniciado la segunda actividad y, por cualquier motivo, el SO decide detener la primera actividad, el contexto utilizado en &lt;code&gt;MyComposable&lt;/code&gt; dejará de ser válido. Por este motivo, es importante evitar enviar el mismo contexto a la segunda actividad &lt;em&gt;(mediante un Bundle)&lt;/em&gt;, para prevenir posibles problemas relacionados con la gestión incorrecta del ciclo de vida del contexto y posibles fugas de memoria.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En Jetpack Compose se suele utilizar una única actividad para la aplicación.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Iniciar Servicios
&lt;/h3&gt;

&lt;p&gt;Si queremos ejecutar un servicio en segundo plano &lt;em&gt;(background)&lt;/em&gt; o en primer plano &lt;em&gt;(foreground)&lt;/em&gt; también usaremos el &lt;code&gt;Context&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tenemos el siguiente servicio:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBackgroundService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;IBinder&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onStartCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;// { ... la logica del servicio }  &lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;START_STICKY&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Su ejecución dentro de una actividad sería de la siguiente forma&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="c1"&gt;// Iniciar el servicio  &lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyBackgroundService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

        &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;En este caso el contexto lo utilizamos para instanciar un &lt;code&gt;Intent&lt;/code&gt; (que este a su vez ejecutará el servicio). El primer parámetro del &lt;code&gt;Intent&lt;/code&gt; es el contexto, como &lt;code&gt;ComponentActivity&lt;/code&gt; extiende de la clase Context, se puede referenciar la misma clase &lt;em&gt;(MainActivity)&lt;/em&gt; mediante &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Utilizarlo en Composables
&lt;/h2&gt;

&lt;p&gt;En el apartado Iniciar Activity se muestra como utilizar el contexto dentro de un composable, la implementación es de la siguiente forma:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;  
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyComposable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;  
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Esta es la forma en la que accedemos al contexto dentro de un composable, dicha forma nos devolverá el contexto ligado a la activity a la que pertenece dicho composable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Utilizarlo en ViewModels
&lt;/h2&gt;

&lt;p&gt;Al utilizar el patrón de diseño MVVM &lt;strong&gt;no&lt;/strong&gt; deberíamos &lt;strong&gt;utilizar&lt;/strong&gt; el &lt;strong&gt;Context&lt;/strong&gt; dentro del &lt;strong&gt;ViewModel&lt;/strong&gt; ya que podría haber &lt;strong&gt;fugas de memoria&lt;/strong&gt; y otra razón es mantener la &lt;strong&gt;separación&lt;/strong&gt; de &lt;strong&gt;responsabilidades&lt;/strong&gt;. También nos ayuda a mantener el código y testearlo mucho mas fácil.&lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;ViewModel&lt;/strong&gt; solo debe encargarse de &lt;strong&gt;almacenar datos&lt;/strong&gt; relacionados con la &lt;strong&gt;vista&lt;/strong&gt; (el composable) y &lt;strong&gt;manejar&lt;/strong&gt; los &lt;strong&gt;datos&lt;/strong&gt; de la vista pero sin implementar el manejo de dichos datos. &lt;/p&gt;

&lt;p&gt;Es decir que él &lt;strong&gt;no&lt;/strong&gt; debe &lt;strong&gt;manejar&lt;/strong&gt; el &lt;strong&gt;acceso&lt;/strong&gt; a una &lt;strong&gt;API&lt;/strong&gt; o una &lt;strong&gt;BBDD&lt;/strong&gt; o a cualquier recurso del sistema Android. &lt;/p&gt;

&lt;p&gt;El ViewModel solo implementará la &lt;strong&gt;lógica ligada&lt;/strong&gt; a la &lt;strong&gt;IU&lt;/strong&gt; y la implementación la hará un Repository y el ViewModel hará uso del Repository.&lt;/p&gt;

&lt;p&gt;Si se necesita utilizar el context dentro del ViewModel se hará de la misma forma, con un Repository que implemente las acciones necesarias y en el ViewModel se utilizará el Repository &lt;em&gt;(inyectándolo por ejemplo)&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PRACTICA POCO RECOMENDADA!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si realmente quieres utilizarlo dentro del ViewModel puedes utilizar inyección de dependencias con Hilt por ejemplo e inyectar el Context en el ViewModel&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/reference/android/content/Context#getApplicationContext()" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.android.com%2F_static%2Fandroid%2Fimages%2Flogo-x.svg" height="480" class="m-0" width="480"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/reference/android/content/Context#getApplicationContext()" rel="noopener noreferrer" class="c-link"&gt;
          Context  |  API reference  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.gstatic.com%2Fdevrel-devsite%2Fprod%2Fv6bfb74446ce17cd0d3af9b93bf26e056161cb79c5a6475bd6a9c25286fcb7861%2Fandroid%2Fimages%2Ffavicon.svg" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://outcomeschool.com/blog/context-in-android-application" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Foutcomeschool.com%2Fstatic%2Fimages%2Fblog%2Fcontext-in-android-application.png" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://outcomeschool.com/blog/context-in-android-application" rel="noopener noreferrer" class="c-link"&gt;
          Context In Android Application
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          In this blog, we will learn about the context in Android application.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Foutcomeschool.com%2Fstatic%2Ffavicons%2Ffavicon-32x32.png" width="32" height="32"&gt;
        outcomeschool.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@banmarkovic/what-is-context-in-android-and-which-one-should-you-use-e1a8c6529652" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AplrvlbqqgynUCHI4H_r3DA.jpeg" alt="Ban Markovic"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@banmarkovic/what-is-context-in-android-and-which-one-should-you-use-e1a8c6529652" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What is Context in Android and which one should you use? | by Ban Markovic | Medium&lt;/h2&gt;
      &lt;h3&gt;Ban Markovic ・ &lt;time&gt;Jan 19, 2020&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>android</category>
      <category>mobile</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Scaffold en Jetpack Compose</title>
      <dc:creator>disced</dc:creator>
      <pubDate>Tue, 04 Apr 2023 10:08:29 +0000</pubDate>
      <link>https://dev.to/dragosb/scaffold-en-jetpack-compose-4a3c</link>
      <guid>https://dev.to/dragosb/scaffold-en-jetpack-compose-4a3c</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--goi6Ce1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8c6ccoge81n23l93c2lv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--goi6Ce1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8c6ccoge81n23l93c2lv.png" alt="Scaffold Jetpack Compose" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Indice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Definición&lt;/li&gt;
&lt;li&gt;Elementos de scaffold&lt;/li&gt;
&lt;li&gt;
Uso básico

&lt;ul&gt;
&lt;li&gt;Función que define el Scaffold&lt;/li&gt;
&lt;li&gt;Barra superior&lt;/li&gt;
&lt;li&gt;Barra inferior&lt;/li&gt;
&lt;li&gt;Botón flotante&lt;/li&gt;
&lt;li&gt;Contenido principal&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Resultado&lt;/li&gt;
&lt;li&gt;Referencias&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Definición
&lt;/h3&gt;

&lt;p&gt;Es un componente de diseño en Android mediante Jetpack Compose &lt;em&gt;(un kit de desarrollo de IU basado en kotlin, una de sus principales funciones es accelerar el desarrollo, usar menos código, que sea mas sencillo, etc)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El uso fundamental de este composable es tener una &lt;strong&gt;estructura estándar&lt;/strong&gt; para los elementos visuales de la app, no es un elemento visual, más bien es un layout. Nos ayuda de manera muy &lt;strong&gt;rápida&lt;/strong&gt; a &lt;strong&gt;posicionar&lt;/strong&gt; &lt;strong&gt;elementos&lt;/strong&gt; comunes en la &lt;strong&gt;pantalla&lt;/strong&gt; sin programarlo de cero. También sigue el patrón de diseño Material Design.&lt;/p&gt;




&lt;h3&gt;
  
  
  Elementos de scaffold
&lt;/h3&gt;

&lt;p&gt;Los elementos que se pueden utilizar en un scaffold son los siguientes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Top app bar&lt;/strong&gt;: es la &lt;strong&gt;barra&lt;/strong&gt; de la parte &lt;strong&gt;superior&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content&lt;/strong&gt;: el &lt;strong&gt;contenido&lt;/strong&gt; principal de la aplicación&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FAB&lt;/strong&gt; &lt;em&gt;(Floating Action Button)&lt;/em&gt;: botón flotante&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottom Bar&lt;/strong&gt;: es la &lt;strong&gt;barra&lt;/strong&gt; de la parte &lt;strong&gt;inferior&lt;/strong&gt;, o barra de navegación&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawer&lt;/strong&gt;: es el &lt;strong&gt;menú lateral&lt;/strong&gt; que se expande/contrae&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Todos ellos son opcionales y personalizables, para hacer utilizar cada elemento, debemos generar un &lt;code&gt;Composable&lt;/code&gt; para dicho elemento, como veremos en el uso básico.&lt;/p&gt;




&lt;h3&gt;
  
  
  Uso básico
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Función que define el Scaffold
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Función Composable que crea un Scaffold personalizado&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;CustomScaffold&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Scaffold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Barra superior&lt;/span&gt;
        &lt;span class="n"&gt;topBar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;CustomTopBar&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt;

        &lt;span class="c1"&gt;// Barra inferior&lt;/span&gt;
        &lt;span class="n"&gt;bottomBar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;CustomBottomBar&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt;

        &lt;span class="c1"&gt;// Botón flotante personalizado&lt;/span&gt;
        &lt;span class="n"&gt;floatingActionButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;CustomFAB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt; 

        &lt;span class="c1"&gt;// Contenido principal&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nc"&gt;CustomContent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;La función &lt;code&gt;Scaffold&lt;/code&gt; tiene bastantes parámetros, yo en este caso he utilizado los siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;topBar&lt;/code&gt;: hace referencia a la barra superior, acepta un &lt;code&gt;Composable&lt;/code&gt; de tipo &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#TopAppBar(kotlin.Function0,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.unit.Dp)"&gt;&lt;code&gt;TopAppBar&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bottomBar&lt;/code&gt;: hace referencia a la barra inferior, por lo general su uso está destinado a la navegación dentro de la aplicación, acepta un &lt;code&gt;Composable&lt;/code&gt; &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#BottomAppBar(androidx.compose.ui.Modifier,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Shape,androidx.compose.ui.unit.Dp,androidx.compose.foundation.layout.PaddingValues,kotlin.Function1)"&gt;&lt;code&gt;BottomAppBar&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;floatingActionButton&lt;/code&gt;: es el botón flotante que se encuentra por encima de todos los demás elementos, se permite fusionar con la barra inferior, acepta un &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#FloatingActionButton(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.foundation.interaction.MutableInteractionSource,androidx.compose.ui.graphics.Shape,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.material.FloatingActionButtonElevation,kotlin.Function0)"&gt;&lt;code&gt;FloatingActionButton&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;content&lt;/code&gt;: hace referencia al contenido principal de la aplicación, se puede poner cualquier &lt;code&gt;Composable&lt;/code&gt; pero se suelen poner filas, columnas, surface, box, etc. En el ejemplo he utilizado &lt;code&gt;Column&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos cuatro parámetros aceptan funciones de tipo &lt;code&gt;@Composable&lt;/code&gt; las que muestro a continuación&lt;/p&gt;


&lt;h4&gt;
  
  
  Barra superior
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;CustomTopBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;TopAppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Título de la barra superior&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Barra inferior
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;CustomBottomBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BottomAppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Contenido de la barra inferior&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Item One"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Botón flotante
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;CustomFAB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Color de fondo&lt;/span&gt;
        &lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MaterialTheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Acción al hacer clic en el botón (sin definir)&lt;/span&gt;
        &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/*TODO*/&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Tamaño de fuente del texto del botón&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"+"&lt;/span&gt; &lt;span class="c1"&gt;// Texto del botón&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Contenido principal
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;CustomContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PaddingValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Modificadores de estilo de la columna&lt;/span&gt;
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
            &lt;span class="c1"&gt;// Ocupar todo el espacio disponible&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxSize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

        &lt;span class="c1"&gt;// Contenido de la aplicación&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My app content"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Resultado
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--03T3e5Og--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82w57v0j9t11erp8gqup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--03T3e5Og--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82w57v0j9t11erp8gqup.png" alt="Scaffold Jetpack Compose result on android device" width="800" height="1649"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Referencias
&lt;/h3&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/tutorial?hl=es-419" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ESTHgKmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/static/images/jetpack/compose-tutorial/lesson2-03.png%3Fhl%3Des-419" height="500" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/tutorial?hl=es-419" rel="noopener noreferrer" class="c-link"&gt;
          Instructivo de Android Compose  |  Jetpack Compose  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/layouts/material?hl=es-419#scaffold" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--eB8Q-Pqb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/lockup-google-for-developers.svg" height="87" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://developer.android.com/jetpack/compose/layouts/material?hl=es-419#scaffold" rel="noopener noreferrer" class="c-link"&gt;
          Componentes y diseños de Material  |  Jetpack Compose  |  Android Developers
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ab7nJBLm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.gstatic.com/devrel-devsite/prod/v01480ab0f36db59e4033b3554acd76a679317609de08cca4b3664f0498a344aa/android/images/favicon.png" width="32" height="32"&gt;
        developer.android.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>android</category>
      <category>jetpackcompose</category>
      <category>kotlin</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
