Introducción a AWS
Crear una aplicación Android
Crear una aplicación Android sencilla con AWS Amplify

crear una aplicación android
Módulo 1: Crear e implementar una aplicación Android
En este módulo, creará una aplicación Android y la implementará en la nube con el servicio de alojamiento web de AWS Amplify.
Introducción
AWS Amplify proporciona un flujo de trabajo basado en Git destinado a crear, administrar, integrar e implementar backends sin servidor para aplicaciones web y móviles. La Command Line Interface (CLI, Interfaz de línea de comandos) de Amplify proporciona una interfaz de usuario simple basada en texto para aprovisionar y administrar servicios de backend, como la autenticación de usuario o una API REST o GraphQL para sus aplicaciones. Las bibliotecas de Amplify permiten integrar fácilmente estos servicios de backend con solo algunas líneas de código en las aplicaciones.
En este módulo, comenzaremos creando una nueva aplicación Android para tomar notas de viaje. Una nota se compone de un título, una descripción y una imagen. Mejoraremos esta aplicación en los siguientes módulos.
Lo que aprenderá
- Crear una aplicación Android
- Actualizar la vista principal para mostrar una lista de elementos
- Crear y probar su aplicación
Conceptos clave
Kotlin: Kotlin fue elegido como el lenguaje de programación para este tutorial porque permite reducir gran parte del código repetitivo y se diseñó con la seguridad de tipos en consideración.
Jetpack: este tutorial utiliza Jetpack de Android, una colección de bibliotecas Android que incorporan las prácticas recomendadas y brindan compatibilidad con versiones anteriores en las aplicaciones Android.
Tiempo de realización
10 minutos
Servicios utilizados
Implementación
-
Crear un proyecto Android
Inicie Android Studio y seleccione Start a new Android Studio project (Iniciar un nuevo proyecto de Android Studio) en la pantalla de presentación.
En Phone and Tablet (Teléfono y tableta), seleccione Basic Activity (Actividad básica) y haga clic en Next (Siguiente).
Escriba un nombre para el proyecto, por ejemplo, Android Getting Started. Asegúrese de que el lenguaje sea Kotlin y el SDK mínimo sea API 26: Android 8.0 (oreo). A continuación, haga clic en Finish (Finalizar).
Ahora que existe el esqueleto del proyecto, debemos seguir cuatro pasos para ejecutar nuestra aplicación básica:
- Eliminar clases y archivos no deseados y agregar complementos
- Crear clases para contener las estructuras de datos
- Crear una clase View para contener la clase Note individual en la lista
- Modificar MainActivity para mostrar una lista de objetos Note
-
Eliminar archivos innecesarios y agregar complementos
En res/layout y java/com.example.androidgettingstarted, elimine los cuatro archivos fragment (seleccione los cuatro archivos, haga clic con el botón derecho y elija Delete [Eliminar] en el menú contextual).
En Gradle Scripts (Scripts de Gradle), abra build.gradle (Module:app) y agregue el complemento de extensión Kotlin.
plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-android-extensions' // <== add this line }
-
Crear una clase de datos UserData
La clase UserData contiene el estado del usuario: un marcador isSignedIn y una lista de valores de notas.
Para crear una nueva clase, haga clic con el botón derecho en java/com.example/androidgettingstarted y seleccione New -> Kotlin file/class (Nuevo -> Archivo/clase Kotlin). Escriba UserData como nombre.
Pegue el siguiente código en el nuevo archivo recién creado (UserData.kt).
package com.example.androidgettingstarted import android.graphics.Bitmap import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData // a singleton to hold user data (this is a ViewModel pattern, without inheriting from ViewModel) object UserData { private const val TAG = "UserData" // // observable properties // // signed in status private val _isSignedIn = MutableLiveData<Boolean>(false) var isSignedIn: LiveData<Boolean> = _isSignedIn fun setSignedIn(newValue : Boolean) { // use postvalue() to make the assignation on the main (UI) thread _isSignedIn.postValue(newValue) } // the notes private val _notes = MutableLiveData<MutableList<Note>>(mutableListOf()) // please check https://stackoverflow.com/questions/47941537/notify-observer-when-item-is-added-to-list-of-livedata private fun <T> MutableLiveData<T>.notifyObserver() { this.postValue(this.value) } fun notifyObserver() { this._notes.notifyObserver() } fun notes() : LiveData<MutableList<Note>> = _notes fun addNote(n : Note) { val notes = _notes.value if (notes != null) { notes.add(n) _notes.notifyObserver() } else { Log.e(TAG, "addNote : note collection is null !!") } } fun deleteNote(at: Int) : Note? { val note = _notes.value?.removeAt(at) _notes.notifyObserver() return note } fun resetNotes() { this._notes.value?.clear() //used when signing out _notes.notifyObserver() } // a note data class data class Note(val id: String, val name: String, val description: String, var imageName: String? = null) { override fun toString(): String = name // bitmap image var image : Bitmap? = null } }
¿Qué acabamos de agregar?
- La clase UserData es responsable de almacenar los datos del usuario, es decir, un marcador isSignedIn para rastrear el estado de autenticación actual y una lista de objetos de Note.
- Estas dos propiedades se implementan de acuerdo con el marco de publicación/suscripción de LiveData. Permite que la Graphical User Interface (GUI, Interfaz gráfica del usuario) se suscriba a los cambios y reaccione en consecuencia. Para obtener más información sobre LiveData, puede leer este documento o mirar este breve video tutorial. Para seguir las prácticas recomendadas, mantenga la propiedad MutableLiveData como privada y solo exponga la propiedad LiveData de solo lectura. Se requiere código repetitivo adicional cuando los datos a publicar son una lista para asegurarse de que se notifique a los observadores cuando se modifiquen los componentes individuales de la lista.
- También agregamos la clase de datos Note solo para contener los datos de las notas individuales. Se utilizan dos propiedades distintas para ImageName e Image. Abordaremos Image en un módulo posterior.
- Se implementó el patrón de diseño singleton para el objeto UserData, ya que permite la referencia a él desde cualquier lugar de la aplicación solo con UserData.
-
Agregar la GUI para las celdas individuales en la lista
Las celdas individuales en una lista de desplazamiento se denominan RecyclerView, ya que la vista se puede reciclar cuando el usuario se desplaza hacia arriba y hacia abajo y cuando ya no es visible en la pantalla.
Al igual que para una vista normal, creamos archivos XML de diseño y una clase Kotlin. Una celda individual se ve así:
Para crear el archivo de diseño, haga clic con el botón derecho en res/layout y seleccione New -> Layout Resource File (Nuevo -> Archivo de recurso de diseño). Escriba content_note como nombre y deje todos los demás valores, ya que editaremos directamente el archivo XML.
Abra la vista Code (Código) para el archivo recién creado.
En la vista Code (Código) del nuevo archivo recién creado (content_note.xml), reemplace el código generado con el siguiente código:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingVertical="16dp"> <ImageView android:id="@+id/image" android:layout_width="100dp" android:layout_height="match_parent" android:padding="8dp" android:scaleType="centerCrop" android:src="@drawable/ic_launcher_background" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="5dp" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/description" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textSize="15sp" /> </LinearLayout> </LinearLayout>
Por último, cree la clase Kotlin: haga clic con el botón derecho en java/com.example/androidgettingstarted y seleccione New -> Kotlin file/class (Nuevo -> Archivo/clase Kotlin). Escriba NoteRecyclerViewAdapter como el nombre.
Pegue el siguiente código en el nuevo archivo que acaba de crear (NoteRecyclerViewAdapter.kt).
package com.example.androidgettingstarted import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView // this is a single cell (row) in the list of Notes class NoteRecyclerViewAdapter( private val values: MutableList<UserData.Note>?) : RecyclerView.Adapter<NoteRecyclerViewAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.content_note, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = values?.get(position) holder.nameView.text = item?.name holder.descriptionView.text = item?.description if (item?.image != null) { holder.imageView.setImageBitmap(item.image) } } override fun getItemCount() = values?.size ?: 0 inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val imageView: ImageView = view.findViewById(R.id.image) val nameView: TextView = view.findViewById(R.id.name) val descriptionView: TextView = view.findViewById(R.id.description) } }
¿Qué acabamos de agregar?
El código anterior está compuesto por los siguientes elementos:- Un archivo XML de diseño que describe el diseño del componente en una celda que representa una Note. Muestra la imagen, el título y la descripción de la nota.
- Una clase Kotlin de respaldo. Recibe un objeto de datos de Note en el momento de la creación y asigna valores individuales a sus vistas correspondientes (imagen, título y descripción).
-
Actualizar la actividad principal
Ahora que tenemos las clases de datos (UserData y Note) y la vista de la nota individual (NoteRecyclerViewAdapter), vamos a crear la lista de notas en la actividad principal.
Desde la lista de archivos a la izquierda de Android Studio, abra res/layout/content_main.xml y reemplace el código con este contenido:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/frameLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <androidx.recyclerview.widget.RecyclerView android:id="@+id/item_list" android:name="com.example.myapplication.ItemListFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="60dp" android:paddingHorizontal="8dp" android:paddingVertical="8dp" app:layoutManager="LinearLayoutManager" tools:context=".MainActivity" tools:listitem="@layout/content_note" /> </FrameLayout>
Desde la lista de archivos a la izquierda de Android Studio, abra java/com.example/androidgettingstarted/MainActivity.kt y reemplace el código con este contenido:
package com.example.androidgettingstarted import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.content_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) // prepare our List view and RecyclerView (cells) setupRecyclerView(item_list) } // recycler view is the list of cells private fun setupRecyclerView(recyclerView: RecyclerView) { // update individual cell when the Note data are modified UserData.notes().observe(this, Observer<MutableList<UserData.Note>> { notes -> Log.d(TAG, "Note observer received ${notes.size} notes") // let's create a RecyclerViewAdapter that manages the individual cells recyclerView.adapter = NoteRecyclerViewAdapter(notes) }) } companion object { private const val TAG = "MainActivity" } }
¿Qué acabamos de agregar?
- El diseño principal es un RecyclerView que administra la lista de celdas individuales que creamos previamente.
- La clase de actividad principal observa los cambios en la lista de Note y crea un NoteRecyclerViewAdapter para crear celdas individuales.
-
Verificar las dependencias de la compilación
En Gradle Scripts (Scripts de Gradle), abra build.gradle (Module:app) y verifique que las dependencias generadas sean correctas. Las `versiones de bibliotecas` deben revisarse.
```gradle dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.2' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
-
Crear y probar
Ahora cree e inicie la aplicación en el simulador. Haga clic en el ícono Run (Ejecutar) ▶️️ en la barra de herramientas o escriba ^ R.
Luego de un momento, la aplicación se inicia en el simulador de Android, con una pantalla inicial vacía.
En esta etapa, no hay datos para representar en el tiempo de ejecución. Nos desharemos del icono de correo en un paso posterior.
Conclusión
Ha creado correctamente una aplicación Android. ¡Está listo para comenzar a crear con Amplify!