Creando actividades en Mis Lugares

La actividad VistaLugarActivity nos mostrará la información que hemos almacenado de un determinado lugar y nos permitirá realizar una gran cantidad de acciones sobre ese lugar (mostrar en mapa, llamar por teléfono, compartir en redes sociales, etc.). Desde esta actividad podremos cambiar algunos valores de modificación frecuente. En concreto: la valoración, la fecha de visita y la fotografía.

Ejercicio: Creación de Ia actividad VistaLugarActivity

1.     Abre el proyecto MisLugares.

2.     Descarga www.androidcurso.com/images/dcomg/mislugares.zip y descomprime en una carpeta. Copia los gráficos que encontrarás en el portapapeles y pegalos dentro de res/drawable en el explorador del proyecto.

3.    Crea un nuevo layout y llámalo vista_lugar.xml. Copia el siguiente código para usarlo como base:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
        <TextView
            android:id="@+id/nombre"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            android:text="Nombres del lugar"
            android:textAppearance="?android:attr/textAppearanceLarge" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >
            <ImageView
                android:id="@+id/logo_tipo"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:contentDescription="logo del tipo"
                android:src="@drawable/otros" />
            <TextView
                android:id="@+id/tipo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="tipo del lugar" />
        </LinearLayout>
      …
        <RatingBar
            android:id="@+id/valoracion"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:rating="3" />
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            <ImageView
                android:id="@+id/foto"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"
                android:contentDescription="fotografía"
                android:src="@drawable/foto_epsg" />
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right" >
            <ImageView
                android:id="@+id/camara"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:contentDescription="logo cámara"
                android:src="@android:drawable/ic_menu_camera" />
            <ImageView
                android:id="@+id/galeria" 

Observa como el elemento exterior es un ScrollView. Esto es conveniente cuando pensemos que los elementos de layout no cabrán en la pantalla. En este caso el usuario podrá desplazar verticalmente el layout arrastrando con el dedo. Dado que algunas pantallas pueden ser muy pequeñas la mayoría de diseños han de incorporar un ScrollView.

Dentro de este elemento tenemos un LinearLayout para organizar las vistas verticalmente. La primera vista es un TextView cuyo id es nombre. Se ha asignado un valor para text inicial, que será reemplazado por el nombre del lugar. La única función que tiene este texto inicial es ayudarnos en el diseño. El siguiente elemento es un LinearLayout vertical que contiene un ImageView y un TextView. Este elemento será utilizado para indicar el tipo de lugar.

Los puntos suspensivos indican el lugar donde tendrás que insertar el resto de elementos que no se han incluido (dirección, teléfono, etc.). El siguiente elemento que se incluye es un RatingBar donde podremos introducir una valoración del lugar. El último elemento es un FrameLayout que permite superponer varias vistas. Se dibujarán en el orden en que las indicamos. En el fondo se dibuja un ImageView con una fotografía de la EPSG. El atributo adjustViewBounds indica que la imagen sea escalada para ocupar todo el espacio disponible. Sobre la fotografía se dibujará un LinearLayout con dos ImageView. Estos botones permitirán cambiar la fotografía desde la cámara o desde la galería.

4.     Reemplaza los puntos suspensivos por los elementos que faltan para obtener la apariencia mostrada al principio de este punto. Para cada elemento haz una copia del <LinearLayout> donde se introduce el tipo de lugar y reemplaza los valores que consideres necesarios. Utiliza los recursos del sistema mostrados en la siguiente tabla. Identifica dada TextView con el id que se indica.

Recurso para ImageView

Id para TextView

@android:drawable/ic_menu_myplaces

@+id/direccion

@android:drawable/ic_menu_call

@+id/telefono

@android:drawable/ic_menu_mapmode

@+id/url

@android:drawable/ic_menu_info_details

@+id/comentario

@android:drawable/ic_menu_my_calendar

@+id/fecha

@android:drawable/ic_menu_recent_history

@+id/hora

5.     Crea la clase VistaLugarActivity y reemplaza el código por el siguiente:

public class VistaLugarActivity extends AppCompatActivity {
   private RepositoriosLugares lugares;
   private CasosUsoLugar usoLugar;
   private int pos;
   private Lugar lugar;

   @Override protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.vista_lugar);
      Bundle extras = getIntent().getExtras();
      pos = extras.getInt("pos", 0);
      lugares = ((Aplicacion) getApplication()).lugares;
      usoLugar = new CasosUsoLugar(this, lugares);
      lugar = lugares.elemento(pos);
      actualizaVistas(pos);
   }
   
   public void actualizaVistas() {
      TextView nombre = findViewById(R.id.nombre);
      nombre.setText(lugar.getNombre());
      ImageView logo_tipo = findViewById(R.id.logo_tipo);
      logo_tipo.setImageResource(lugar.getTipo().getRecurso());
      TextView tipo = findViewById(R.id.tipo);
      tipo.setText(lugar.getTipo().getTexto());
      TextView direccion = findViewById(R.id.direccion);
      direccion.setText(lugar.getDireccion());
      TextView telefono = findViewById(R.id.telefono);
      telefono.setText(Integer.toString(lugar.getTelefono()));
      TextView url = findViewById(R.id.url);
      url.setText(lugar.getUrl());
      TextView comentario = findViewById(R.id.comentario);
      comentario.setText(lugar.getComentario());
      TextView fecha = findViewById(R.id.fecha);
      fecha.setText(DateFormat.getDateInstance().format(
            new Date(lugar.getFecha())));
      TextView hora = findViewById(R.id.hora);
      hora.setText(DateFormat.getTimeInstance().format(
            new Date(lugar.getFecha())));
      RatingBar valoracion = findViewById(R.id.valoracion);
      valoracion.setRating(lugar.getValoracion());
      valoracion.setOnRatingBarChangeListener(
            new OnRatingBarChangeListener() {
                @Override public void onRatingChanged(RatingBar ratingBar, 
                                         float valor, boolean fromUser) {
                   lugar.setValoracion(valor);
                }
      });
   }
}  
class VistaLugarActivity : AppCompatActivity() {
   val lugares by lazy { (application as Aplicacion).lugares }
   val usoLugar by lazy { CasosUsoLugar(this, lugares) }
   var pos = 0
   lateinit var lugar: Lugar

   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.vista_lugar)
      pos = intent.extras?.getInt("pos", 0) ?: 0
      lugar = lugares.elemento(pos)
      actualizaVistas()
   }

   fun actualizaVistas(){
      nombre.text = lugar.nombre
      logo_tipo.imageResource = lugar.tipoLugar.recurso
      tipo.text = lugar.tipoLugar.texto
      direccion.text = lugar.direccion
      telefono.text = Integer.toString(lugar.telefono)
      url.text = lugar.url
      comentario.text = lugar.comentarios
      fecha.text = DateFormat.getDateInstance().format(Date(lugar.fecha))
      hora.text = DateFormat.getTimeInstance().format(Date(lugar.fecha))
      valoracion.rating = lugar.valoracion
      valoracion.setOnRatingBarChangeListener { 
         ratingBar, valor, fromUser -> lugar.valoracion = valor
      }
   }
}  

Nota sobre Java/Kotlin: Pulsa Alt-Intro  para que automáticamente se añadan los imports con los  paquetes que faltan. Dos clases aparecen en varios paquetes, selecciona java.text.DateFormat y java.util.Date.

Se definen tres variables globales para que se pueda acceder a ellas desde cualquier método de la clase: lugares corresponde con el repositorio de lugares, cuya referencia se obtiene desde Application, pos es la posición del elemento que vamos a visualizar y lugar es el elemento en sí.

El método onCreate() será ejecutado cuando se cree la actividad y en el tenemos que asociar un layout (setContentView(R.layout.vista_lugar)) e inicializar todos sus valores. A continuación, se averigua la posición del lugar a mostrar, que ha sido pasado en un extra. A partir de este id obtenemos el objeto Lugar a mostrar.

En java observa cómo se obtiene un objeto de cada uno de los elementos de la vista utilizando el método findViewById(). En Kotlin esta operación e realiza de forma automática. A continuación este objeto es modificado según el valor del lugar que estamos representando. Al final se realiza una acción especial con el objeto valoracion, utilizando el método setOnRatingBarChangeListener() para asignarle un escuchador de eventos al RatingBar que es creado allí mismo. Este escuchador de evento se activará cuando el usuario modifique la valoración. El código a ejecutar consiste en modificar la propiedad Valoracion() del objeto lugar con la nueva valoración.

6.     Abre la clase TipoLugar y asigna un recurso drawable a cada tipo de lugar. Puedes utilizar la opción de autocompletar, es decir, escribe R.drawable. y espera a que el sistema te dé una alternativa.

public enum TipoLugar {
    OTROS ("Otros", R.drawable.otros),
    RESTAURANTE ("Restaurante", R.drawable.restaurante),
    BAR("Bar", R.drawable.bar),
    …

7.     Añade en MainActivity el siguiente método:

public void lanzarVistaLugar(View view){
  usoLugar.mostrar(0);
} 
fun lanzarVistaLugar(view: View? = null) {
    usoLugar.mostrar(0) 
} 

Este método lanzará la actividad VistaLugarActivity pasándole como posicion del lugar a visualizar siempre 0. Más adelante mostraremos algunas alternativas para que el usuario pueda seleccionar el lugar a mostrar.

8.     En el método onOptionsItemSelected() de la actividad MainActivity añade el siguiente código:

@Override public boolean onOptionsItemSelected(MenuItem item) {
   int id = item.getItemId();
   …
   if (id == R.id.menu_buscar) {
      lanzarVistaLugar(null);
      return true;
   }
   …
} 
override fun onOptionsItemSelected(item: MenuItem): Boolean {
   return when (item.itemId) {
      …
      R.id.menu_buscar -> {
         lanzarVistaLugar()
         true;
      }

9.     Ejecuta la aplicación. Aparecerá un error cuando selecciones Buscar. Siempre que aparezca un error en ejecución es el momento de visualizar el LogCat. No es sencillo analizar la información que se muestra, pero es muy importante que te acostumbres a buscar la causa del problema en el LogCat. En este caso la información clave se muestra a continuación:

>

10.     Para resolver el error en ejecución registra la nueva actividad en AndroidManifest.xml

11.     Ejecuta la aplicación y verifica que cuando seleccionas el icono buscar se arranca una actividad que muestra el primer lugar.

Ejercicio: Un cuadro de dialogo para indicar el id de lugar

Tras realizar el ejercicio anterior comprobarás que siempre se visualiza el lugar con posición 0. En este ejercicio vamos a introducir un cuadro de dialogo que permita introducir al usuario el id que desea visualizar.

Ha de quedar claro que esta es la forma más correcta de diseñar el interfaz de usuario. En la siguiente unidad reemplazaremos este cuadro de dialogo por un RecyclerView.

1.      Abre la clase MainActivity del proyecto MisLugares.

2.      Reemplaza el método por el lanzar LanzaVistaLugar() siguiente:

public void lanzarVistaLugar(View view){
    final EditText entrada = new EditText(this);
    entrada.setText("0");
    new AlertDialog.Builder(this)
       .setTitle("Selección de lugar")
       .setMessage("indica su id:")
       .setView(entrada)
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int whichButton) {
               int id = Integer.parseInt (entrada.getText().toString());
             usoLugar.mostrar(id);
           }})
       .setNegativeButton("Cancelar", null)
       .show();
} 
fun lanzarVistaLugar(view: View? = null) {
   val entrada = EditText(this)
   entrada.setText("0")
   AlertDialog.Builder(this)
      .setTitle("Selección de lugar")
      .setMessage("indica su id:")
      .setView(entrada)
      .setPositiveButton("Ok")  { dialog, whichButton ->
         val id = parseInt(entrada.text.toString())
          usoLugar.mostrar(id);
      }
      .setNegativeButton("Cancelar", null)
      .show()
} 

  Nota sobre Java/Kotlin: En Java es posible crear un objeto sin que este disponga de un identificador de objeto. Este tipo de objeto se conoce como objeto anónimo. El código mostrado a continuación a la derecha es equivalente al de la izquierda.

Clase objeto = new Clase();         new Clase().metodo();
        objeto.metodo(); 
 objeto: Clase = Clase()             Clase().metodo()
        objeto.metodo(); 

Un objeto anónimo no tiene identificador por lo que solo puede ser usado donde se crea. En el método anterior se ha creado un objeto anónimo de la clase AlertDialog.Builder.Observa cómo no se llama a un método, sino a una cadena de métodos. Esto es posible porque los métodos de la clase AlertDialog.Builder  retornan el objeto  que estamos creando. Por lo tanto, cada método es aplicado al objeto devuelto por el método anterior.

En Android puedes usar la clase AlertDialog para crear un cuadro de dialogo configurable. Si te fijas en la captura anterior están formados por cuatro elementos, de arriba abajo: título, mensaje, vista y botones. Estos elementos pueden ser configurados mediante los método setTitle(), setMessage(), setView(), setPositiveButton() y setNegativeButton().

La vista que se utiliza en este diálogo es un EditText, inicializado con un texto. En caso de necesitar varias entradas se puede crear una vista de tipo layout, que contendría estas entradas. Se han introducido dos botones, indicando el texto del botón y un escuchador de evento que será llamado cuando se pulse el botón. Finalmente se llama al método show() para que se visualice el cuadro de diálogo.

3.      Verifica que funciona correctamente. Pero cuidado, no se verifica que el id sea válido, por lo que ocurrirá un error si es incorrecto.

 Práctica: Ocultar elementos en VistaLugarActivity

En ocasiones no se dispondrá de parte la información de un lugar. En estos casos, puede resultar más conveniente desde un punto de vista estético, no mostrar campos sin información en VistaLugarActivity. Por ejemplo, si el campo de teléfono es igual a 0, podríamos usar el siguiente código para que no se muestre:

if (lugar.getTelefono() == 0) {
    findViewById(R.id.telefono).setVisibility(View.GONE);
} else {
    findViewById(R.id.telefono).setVisibility(View.VISIBLE);
    TextView telefono = findViewById(R.id.telefono);
    telefono.setText(Integer.toString(lugar.getTelefono()));
 } 
if (lugar.telefono == 0) {
   telefono.setVisibility(View.GONE)
} else {
   telefono.setVisibility(View.VISIBLE)
   telefono.setText(Integer.toString(lugar.telefono))
} 

Para ocultarlo, en el layout telefono, ponemos el valor propiedad visibility al valor GONE Este atributo es aplicado a cualquier tipo de vista. Otros posibles valores para este atributo son VISIBLE e INVISIBLE. Tanto con GONE como con INVISIBLE la vista no se verá. Pero con INVISIBLE el espacio ocupado por la vista se mantiene, mientras que con GONE este espacio se elimina.

Trata de realizar un proceso similar a este para los campos dirección, telefono, url y comentario. Para verificar si un  String es vacío puedes usar el método isEmpty().

Ejercicio: Añadir una barra de acciones a VistaLugarActivity

En este ejercicio vamos a añadir a la actividad un menú a la barra de acciones similar al que se muestra a continuación:

1.     En primer lugar crea el fichero res/menu/vista_lugar.xml que contendrá las acciones a mostrar. Para ello pulsa con el botón derecho sobre la carpeta res/menu y crea el fichero vista_lugar.

2.     Reemplaza su contenido por el siguiente código:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/accion_compartir"
        android:title="compartir"
        android:icon="@android:drawable/ic_menu_share"
        android:orderInCategory="10"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/accion_llegar"
        android:title="cómo llegar"
        android:icon="@android:drawable/ic_menu_directions"
        android:orderInCategory="20"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/accion_editar"
        android:title="editar"
        android:icon="@android:drawable/ic_menu_edit"
        android:orderInCategory="30"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/accion_borrar"
        android:title="borrar"
        android:icon="@android:drawable/ic_menu_delete"
        android:orderInCategory="40"
        app:showAsAction="ifRoom"/>
</menu> 

3.     En la clase VistaLugarActivity añade los siguientes métodos:

@Override public boolean onCreateOptionsMenu(Menu menu) {
   getMenuInflater().inflate(R.menu.vista_lugar, menu);
   return true;
}

@Override public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
   case R.id.accion_compartir:
      return true;
   case R.id.accion_llegar:
      return true;     
   case R.id.accion_editar:
      return true;
   case R.id.accion_borrar:
      usoLugar.borrar(pos);
      return true;
   default:
      return super.onOptionsItemSelected(item);
   }
} 
override fun onCreateOptionsMenu(menu: Menu): Boolean {
   menuInflater.inflate(R.menu.vista_lugar, menu)
   return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
   when (item.getItemId()) {
      R.id.accion_compartir -> return true
      R.id.accion_llegar -> return true
      R.id.accion_editar -> return true
      R.id.accion_borrar -> {
         usoLugar.borrar(pos)
         return true
      }
      else -> return super.onOptionsItemSelected(item)
   }
} 

4.     Añade a CasosUsoLugares:

public void borrar(final int id) {
   lugares.borrar(id) 
   actividad.finish();
} 
fun borrar(id: Int) {
   lugares.borrar(id)
   actividad.finish()
} 

5.     Ejecuta la aplicación y borra un lugar. Verifica que, si tratas de visualizar el mismo id ahora se muestra el siguiente lugar.

 Práctica: Un cuadro de diálogo para confirmar el borrado

Un usuario podría pulsar por error el botón de borrar, por lo que sería muy conveniente pedir una confirmación antes de borrar.

1.     En el método crea un cuadro de dialogo siguiendo el esquema planteado en el ejercicio anterior. Puede ser similar al siguiente.

Creando la actividad EdicionLugarActivity

En este apartado crearemos otra actividad en la aplicación Mis Lugares, EdicionLugarActivity. Esta actividad nos permitirá modificar la mayoría de valores asignados a un lugar (se excluyen los valores que se modifican desde VistaLugarActivity: Valoración, fecha y foto):

Práctica: Creación de la actividad EdicionLugarActivity

1.     En el proyecto MisLugares verifica que existe el layout edicion_lugar.xml. En caso contrario realiza la práctica “Creación de Mis Lugares y formulario de edición”.

2.     Crea la clase EdicionLugarActivity y haz  que extienda AppCompatActivity. Copia en esta clase los atributos y los método onCreate() y actualizaVistas() de la clase  VistaLugarActivity.

3.     En Java añade los siguientes atributos a la clase:

 private EditText nombre;
 private Spinner  tipo;
 private EditText direccion;
 private EditText telefono;
 private EditText url;
 private EditText comentario;

De esta forma estos seis objetos serán accesibles desde cualquier método de la clase, en lugar de estar declarados solo en el método onCreate().

En Kotlin este proceso se realiza automáticamente.

4.     Reemplaza la vista a mostrar en setContentView() por edicion_lugar.

5.     El paso de parámetros para obtener pos y lugar puede realizarse de la misma forma.

6     Si has realizado la práctica “Ocultar elementos en VistaLugarActivity”, has de eliminar el código introducido. Por ejemplo, en el caso del campo del teléfono elimina el código tachado:

if (lugar.getTelefono() == 0) {
   findViewById(R.id.telefono).setVisibility(View.GONE);
} else {
   findViewById(R.id.telefono).setVisibility(View.VISIBLE);
   telefono = findViewById(R.id.telefono);
   telefono.setText(Integer.toString(lugar.getTelefono()));
} 

7.    Puedes eliminar el resto del código de este método, que hace referencia a logo_tipo, tipo, fechahora y valoración.

8.    Crea un caso de uso, con la función editar(pos) que abra la actividad que acabas de crear. Usa mostrar(pos) como referencia.

9.     En la clase VistaLugarActivity  dentro del método onOptionsItemSelected(), añade el código necesario para que se abra la actividad que acabas de crear se llame a esta función.

10.     Ejecuta el proyecto. Pero antes, piensa si falta alguna acción por realizar.

Ejercicio: Inicializar el Spinner en EdicionLugarActivity

Como has podido verificar en la ejecución anterior el Spinner (lista desplegable) no muestra ningún valor. En este ejercicio trataremos que funcione adecuadamente:

1.     Añade el siguiente código el método onCreate():

tipo = findViewById(R.id.tipo);
ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this,
         android.R.layout.simple_spinner_item, TipoLugar.getNombres());
adaptador.setDropDownViewResource(android.R.layout.
         simple_spinner_dropdown_item);
tipo.setAdapter(adaptador);
tipo.setSelection(lugar.getTipo().ordinal()); 
val adaptador = ArrayAdapter<String>(this,
   android.R.layout.simple_spinner_item,
   lugar.tipoLugar.getNombres()
)
adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
tipo.adapter = adaptador
tipo.setSelection(lugar.tipoLugar.ordinal) 

Para inicializar los valores que puede tomar un Spinner necesitamos una clase especial conocida como Adapter. Esta clase se estudiará en la siguiente unidad. De momento solo adelantamos que un Adapterva a crear una lista de vistas, inicializándolas con unos valores determinados. La clase ArrayAdapter<String> es un tipo de Adapter que permite inicializar sus valores a partir de un array de String. Su constructor necesita tres parámetros: un contexto (usamos la actividad actual), una vista para mostrar elemento (usamos un vista definida en el sistema) y un array de String. Para el último parámetro necesitamos un array con todos los valores que puede tomar el enumerado TipoLugar. Para obtener este array se define un nuevo método que se muestra a continuación.

El siguiente método, setDropDownViewResource(), permite indicar una vista alternativa que se usará cuando se despliegue el Spinner. En la versión 4.x esta vista es un poco más grande que la usada en el método anterior para poder seleccionarla cómodamente con el dedo. En la versión 2.x muestra círculos seleccionables a la derecha de cada elemento. Este código concluye asignando el adaptador al Spinner y poniendo un valor inicial según el tipo actual de lugar.

2.     Añade el siguiente método a la clase TipoLugar:

public static String[] getNombres() {
   String[] resultado = new String[TipoLugar.values().length];
   for (TipoLugar tipo : TipoLugar.values()) {
      resultado[tipo.ordinal()] = tipo.texto;
   }
   return resultado;
} 
fun getNombres(): Array<String?> {
   val resultado = arrayOfNulls<String>(TipoLugar.values().size)
   for (tipo in TipoLugar.values()) {
      resultado[tipo.ordinal] = tipo.texto
   }
   return resultado
} 

3.    Ejecuta la aplicación y verifica que la lista desplegable funciona correctamente..

Práctica: Añadir una barra de acciones a EdicionLugarActivity

En esta práctica vamos a añadir a la actividad un menú en la barra de acciones similar al que se muestra a continuación:

1.     Crea un nuevo recurso de menú con las opciones que se indican.

2.     Asocia este menú a la actividad EdicionLugarActivity con el método onCreateOptionsMenu().<

3.     Crea el método onOptionsItemSelected() de manera que cuando se seleccione la acción Guardar se ejecute el siguiente código:

lugar.setNombre(nombre.getText().toString());
lugar.setTipo(TipoLugar.values()[tipo.getSelectedItemPosition()]);
lugar.setDireccion(direccion.getText().toString());
lugar.setTelefono(Integer.parseInt(telefono.getText().toString()));
lugar.setUrl(url.getText().toString());
lugar.setComentario(comentario.getText().toString());
usoLugar.guardar(pos,Lugar) 
finish(); 
val nuevoLugar = Lugar(nombre.text.toString(), direccion.text.toString(),
        lugar.posicion, TipoLugar.values()[tipo.selectedItemPosition],
        lugar.foto, Integer.parseInt(telefono.text.toString()),
        url.text.toString(), comentario.text.toString(),
        lugar.fecha, lugar.valoracion )
usoLugar.guardar(pos, nuevoLugar) 
finish() 

4.    Cuando se seleccione la acción cancelar, simplemente se saldrá de la actividad.

5.    Añade a CasosLugar la siguiente función:

void guardar(int id, Lugar nuevoLugar) {
   lugares.actualiza(id, Lugar);
} 
fun guardar(id: Int, nuevoLugar: Lugar) {
   lugares.actualiza(id, nuevoLugar)
} 

5.    Ejecuta la aplicación. Modifica algún lugar y pulsa en Guardar. Al regresar a la actividad anterior los valores permanecen sin variación. Sin embargo si pulsas la tecla volver y entras a visualizar el mismo lugar, los cambios sí que son actualizados. ¿Qué puede estar pasando?

Ejercicio: Refrescar VistaLugarActivity tras entrar en  EdicionLugarActivity

Parece que al regresar a VistaLugarActivity  desde EdicionLugarActivity no estamos indicando que vuelva a obtener los datos mostrados en las vistas. Para actualizar estos valores puedes hacer los siguientes pasos:

1.     Añade el código subrayado en CasosUsoLugar:

public void editar(int pos, int codidoSolicitud) {
   Intent i = new Intent(actividad, EdicionLugarActivity.class);
   i.putExtra("pos", pos);
   actividad.startActivityForResult(i, codidoSolicitud);
} 
fun editar(pos: Int, codidoSolicitud: Int) {
   val i = Intent(actividad, EdicionLugarActivity::class.java)
   i.putExtra("pos", pos);
   actividad.startActivityForResult(i, codidoSolicitud)
} 

2.     Añade la siguiente constante a VistaLugarActivity

final static int RESULTADO_EDITAR = 1;
val RESULTADO_EDITAR = 1

3.     En el método onOptionsItemSelected() añade el nuevo parámetro.

4.     Añade el siguiene método:VistaLugarActivity

@Override protected void onActivityResult(int requestCode, int resultCode, 
                Intent data) {
   if (requestCode == RESULTADO_EDITAR) {
      actualizaVistas();
      findViewById(R.id.scrollView1).invalidate();
   }
} 
override fun onActivityResult(requestCode: Int, resultCode: Int, 
                data: Intent?) {
   if (requestCode == RESULTADO_EDITAR) {
      actualizaVistas()
      scrollView1.invalidate()
   }
} 

Una vez regresamos de la actividad EdicionLugarActivity lo que hacemos es actualizar los valores de las vistas y forzar al sistema a que repinte la vista con id scrollView1. Esta vista corresponde al ScrollView que contiene todo el layout.