Busqueda de peliculas REST - parte cliente




Cliente

Diseño de la vista

En una primera iteración podemos pensar la vista lo más simple posible:
  • un campo editable para ingresar el título de la película
  • un botón para disparar la consulta
  • y un listView para mostrar los resultados

Para una segunda iteración vamos a incorporar un checkbox, que nos permitirá disparar la búsqueda a medida que escribamos en el campo editable.

Cómo se dispara la consulta

En el evento onCreate instanciamos la llamada:

   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // IMPORTANTE
        // Por un bug de retrofit 2.0, la BASE_URL debe tener una / al final
        // y la dirección del service debe comenzar sin /, como un path relativo
        String BASE_URL = "http://10.0.2.2:8080/videoclub-ui-grails-homes-xtend/";

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        peliculaService = retrofit.create(PeliculasService.class);
    }
PeliculaListFragment.java

Definimos que la activity implemente la interfaz OnClickListener y el método onClick(View v) dispara la búsqueda en un método específico llamado buscarPeliculas():

    @Override
    public void onClick(View v) {
        buscarPeliculas();
    }

PeliculaListFragment.java


En la interfaz PeliculasService indicamos que 
  • la búsqueda se hace mediante un método GET
  • y le pasamos como parámetro el valor que tiene el EditText
public interface PeliculasService {

    @GET("peliculas/{tituloContiene}")
    public Call<List<Pelicula>> getPeliculas(@Path("tituloContiene") String tituloContiene);

}

PeliculasService.java


Pero  ¿cuándo le pasamos el valor del EditText? Al invocar el servicio:

    private void buscarPeliculas() {
        EditText campoBusqueda = (EditText) this.getView().findViewById(R.id.tituloContiene);
        String titulo = campoBusqueda.getText().toString();

        Call<List<Pelicula>> peliculaCall = peliculaService.getPeliculas(titulo);

        peliculaCall.enqueue(new Callback<List<Pelicula>>() {
            @Override
            public void onResponse(Response<List<Pelicula>> response, Retrofit retrofit) {
                List<Pelicula> peliculas = response.body();

                setListAdapter(new PeliculaAdapter(
                        getActivity(),
                        peliculas));

            }

            @Override
            public void onFailure(Throwable t) {
                t.printStackTrace();
                Log.e("PeliculasApp", t.getMessage());
            }
        });
    }
PeliculaListFragment.java


Además, hacemos la llamada asincrónica, definiendo dos métodos:
  • onResponse: si tenemos una respuesta, una lista de películas que viene en el body como JSON
  • onFailure: donde recibimos una excepción (algo mejor que un 500, ó un 404)
El JSON encaja perfectamente en nuestra definición de una lista de películas:


 JSON
 
  1. [{
  2. "titulo": "Jardines en otoño",
  3. "actores": "Séverin Blanchet, ...",
  4. "genero": {
  5. "id": 1,
  6. "descripcion": "Drama"
  7. }
  8. },
 objeto de dominio Película en Java


public class Pelicula {

    String titulo;

    String actores;

    Genero genero;


 objeto de dominio Género en Java

public class Genero {

String descripcion;


Cómo llenar el ListView de películas

Una vez que tenemos la lista de películas en nuestro ambiente de Android, el comportamiento es igual que en la ventana master.

Un último agregado

Y finalmente vamos a incorporarle el checkbox a la vista,
  • si el checkbox está activado esto disparará la búsqueda automáticamente cada vez que el usuario escriba algo (y siempre que haya al menos dos caracteres en el texto). Para eso necesitamos definir un TextWatcher (un Observer) sobre el campo editable.
    • no tiene sentido entonces mostrar un botón para disparar la búsqueda (se invisibiliza)
  • si el checkbox está desactivado hay que mostrar el botón y permitir que se dispare manualmente la búsqueda
Primero vamos a la vista (res/layout/activity_peliculas.xml) e incorporamos el checkbox. Luego modificamos el método onCreate de nuestra Activity principal para que se comporte como describimos recién:


    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Restore the previously serialized activated item position.
        if (savedInstanceState != null
                && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
        }

        // Comportamiento del checkbox que indica si se busca a medida que se escribe
        final CheckBox chkBuscar = (CheckBox) view.findViewById(R.id.chkBuscarOnline);
        final View myView = view;
        chkBuscar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ImageButton btnBuscar = (ImageButton) myView.findViewById(R.id.btnBuscar);
                if (chkBuscar.isChecked()) {
                    btnBuscar.setVisibility(View.INVISIBLE);
                } else {
                    btnBuscar.setVisibility(View.VISIBLE);
                }
            }
        });

        // Comportamiento del título de búsqueda
        EditText tituloContiene = (EditText) view.findViewById(R.id.tituloContiene);
        tituloContiene.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable editable) {
                if (chkBuscar.isChecked() && editable.length() >= MIN_BUSQUEDA_PELICULAS) {
                    buscarPeliculas();
                }
            }
        });

        ((ImageButton) view.findViewById(R.id.btnBuscar)).setOnClickListener(this);
    }
PeliculaListFragment.java

Ver una película

Cuando el usuario selecciona una película, disparamos un Intent que muestra sus datos, como se explicó en la vista de detalle.

Arquitectura general


Comments