Comunidad de diseño web y desarrollo en internet online

Introducción a la programación en Android L

Google I/O 2014 será recordado por ser uno de los más android-céntricos de todos, no solo presentando novedades a nivel de móviles como estábamos acostumbrados, si no incursionando en campos nuevos para la plataforma como: wearables y automóviles. Además, por primera vez, una versión Developer Preview llamada: Android L, para que podamos experimentar con el SDK y generar el mayor feedback posible, antes del lanzamiento oficial en dispositivos.



Android L es uno de los cambios más grandes que a tenido Android en mucho tiempo, lo que se siente como una verdadera actualización más que una extensión. Dichos cambios a grosso modo se dividen en:
    Una nueva UI:


    Se estrena Material Design, por lo que ahora, tanto el operativo, como las aplicaciones deben de seguir los principios del nuevo lenguaje de diseño de Google. Material Design contiene todos los elementos a nivel de UI, movimiento e interacción, para generar UX nunca vista en la plataforma. Además se agregan 2 nuevos widgets:



      CardView:
      Nos permite agrupar casi cualquier tipo y número de elementos en una vista que, al final, resulta un tipo “Tarjeta” como lo visto en Google Now. Al venir de la librería de soporte, este nuevo widget funciona igual en versiones anteriores a L.

      RecyclerView:
      Una actualización de ListView. Esta vez es mas fácil de usar, optimiza recursos, y ofrece animaciones predeterminadas. Útil para su uso en colecciones dinámicas (ListView y GridView).

      Haciendo que todo fluya como la seda, sin embargo, las aplicaciones ahora requieren más espacio de almacenamiento en tu dispositivo, pero velocidad y optimización de batería lo valen.

Nuevo Runtime:
ART (Android RunTime) se vuelve la máquina virtual por defecto sustituyendo a Dalvik, incluye tres importantes cambios:
    Compilación por delante del tiempo.
    Mejora del recolector de basura.
    Mejora las opciones de debug.

Renovado Sistema de Notificaciones:

Las notificaciones es algo que a tenido Android desde su primera versión, ahora no solo siguen los principios de Material Design, sino que, tenemos disponibles nuevos valores para ellas:
    Visibilidad privada:
    Muestra información básica, como el icono de la notificación, pero oculta el contenido completo de la notificación.
    Visibilidad publica:
    Muestra el contenido completo de la notificación.
    Visibilidad secreta:
    No muestra más que el icono de la notificación en la barra de estado.

Incremento de Eficiencia:

Sumado a todo, se agregaron elementos que ayudan a monitorear nuestra aplicación y consultar varios estados de ella, tal es el caso de Project Volta, un API capaz de mostrarnos el consumo de energía a nivel de aplicación, así podemos parar o matar los procesos que están consumiendo mas recursos de los necesarios o que no es necesario que se estén ejecutando.

Tu primera aplicación en Android L


Ahora, vamos a crear una aplicación con algunas de las novedades de Android L. La aplicación simulará un feed de los cursos de Mejorando.la. Usaremos los dos nuevos widgets: Card View y Recycler View, ademas de un Float Button, todo siguiendo los principios del nuevo Material Design. Es complicado hacer un tutorial paso a paso de ciertos temas extras que contiene la aplicación y solo hare énfasis en los temas nuevos de Android L.

El código se encuentra disponible en: https://github.com/thespianartist/FeedCursosMejorandola





    Requerimientos

    Android Studio Beta (Su version mas reciente)



    Dispositivo corriendo Android L o en su defecto crear una Máquina Virtual con dicho nivel de API.

    Con el SDK Manager tener instalados:
      Android SDK Platform-Tools 20
      Android SDK Build-Tools 20
      SDK Platform Android L (API 20, L Preview) y cualquier System Image si se requiere una máquina virtual.
      Android Support Library 20
      Android Support Repository 6








    Ya verificando que se tienen todo instalado, podremos crear un nuevo proyecto “Hola mundo” con ese nivel de API para comprobar que todo esta bien, el ejemplo que usaremos, solo contiene una actividad con un fragmento en ella.



    Declarando el tema: Material Design

    Lo único que necesitamos para que una aplicación tenga aspecto Material Design es el configurarlo como tema. Si observamos los archivos de styles.xml, contenidos en las diferentes carpetas de values, en la carpeta donde se guardan todos los recursos no java res nos daremos cuenta que tenemos disponible un nuevo tema parent llamado: Material.

    Material tiene las mismas variaciones de Holo (como Light con Dark ActionBar) pero ademas, nos ayuda a personalizar los colores de la UI de manera más sencilla. De inmediato podemos asignar 3 campos al tema: colorPrimary, colorPrimaryDark y accent.



    colorPrimary debe ser el color característico de la marca a la que pertenece la aplicación, colorPrimaryDark su variación un poco más oscura pero nada ajeno al color primario original y por último accent será un color que resalte sobre toda nuestra aplicación y lo hace un contraste interesante, para más información sobre los colores a usar visita http://www.google.com/design/spec/style/color.html

    Ahora también podemos declarar algunos valores globales de color para que sean utilizados en cualquier parte de la aplicación gracias a la etiqueta<color>. En el ejemplo configuramos los 3 valores de color de personalización de tema, ademas de un cuarto color que corresponde al color que usaremos en el Float Button. La imagen de abajo describe la personalización completa de la aplicación en styles.xml:

    Código :

        <resources>
            <!-- Base application theme. -->
            <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
                <item name="android:colorPrimary">@color/primary</item>
                <!--   darker variant of colorPrimary (for status bar, contextual app bars) -->
                <item name="android:colorPrimaryDark">@color/primary_dark</item>
                <!--   theme UI controls like checkboxes and text fields -->
                <item name="android:colorAccent">@color/accent</item>
            </style>
    
            <color name="primary_dark">#056f00</color>
            <color name="primary">#259b24</color>
            <color name="accent">#ffea00</color>
            <color name="acent_button">#ffff00</color>
        </resources>
    
    


    Uso de CardView

    Para usar los dos nuevos widgets necesitamos compilar las dependencias correspondientes, estas se encuentra dentro de el conjunto de librerías de soporte y pueden ser incluidas de la siguiente manera, en el archivo build.gradle de la raíz del directorio app:



    El uso de CardView es muy sencillo, al final se trata de un widget que otorga dicho UI a lo que se encuentre entre el. Uno de sus atributos es el poder asignar bordes redondeados a la carta: card_view:cardCornerRadius="2dp". Ademas existe un atributo android:foreground="?android:attr/selectableItemBackground" para que la tarjeta obtenga la animación característica de Material Design al hacer clic sobre ella. La vista que tenemos como preview es la de un curso sin datos, a esto lo llamaremos itemLayout (row.xml) y será usado para nuestro RecyclerView.



    En el ejemplo, cada curso se muestra como tarjeta, dicho curso esta compuesto de un ImageView y 2 TextView acomodados mediante un RelativeLayout. Lo único que falta para que dicho UI tome forma de tarjeta es, como mencione anteriormente, colocarlos entre las etiquetas <android.support.v7.widget.CardView> con la configuración que usted quiera. En el ejemplo se consideró de la siguiente manera:

    Código :

    <?xml version="1.0" encoding="utf-8"?>
    
    <android.support.v7.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:foreground="?android:attr/selectableItemBackground"
        android:clickable="true"
        android:layout_margin="10dp"
        android:id="@+id/card_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="2dp">
    
                <RelativeLayout
    
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">
    
                    <ImageView
                        android:src="@drawable/backend"
                        android:layout_width="150dp"
                        android:layout_height="150dp"
                        android:scaleType="centerCrop"
                        android:id="@+id/image"/>
    
                                <TextView
                                    android:paddingLeft="10dp"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:textAppearance="?android:attr/textAppearanceLarge"
                                    android:text="Large Text"
                                    android:id="@+id/name"
                                    android:layout_alignParentTop="true"
                                    android:layout_toEndOf="@+id/image" />
    
                                <TextView
                                    android:paddingLeft="10dp"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="Large Text"
                                    android:id="@+id/description"
                                    android:layout_below="@+id/name"
                                    android:layout_toEndOf="@+id/image" />
    
                </RelativeLayout>
    
    </android.support.v7.widget.CardView>


    Uso de RecyclerView

    RecyclerView es una mejora de lo antes visto en ListView o GridView. Es un widget que despliega vistas que comparten la misma estructura de vista de los datos, ósea , son vistas que se “repiten” en forma, pero no en información.
    RecyclerView nos proporciona unLayoutManager que es el encargado de asignar el acomodo de los elementos (Grid o Linear), aunque por el momento solo esta disponible Linear (como lista). Para que esto funcione necesitamos construir nuestro Adapter y a su vez, el Adapter necesita de un Dataset, ósea un conjunto (arreglo) de objetos.



    El Dataset requiere de un arreglo de objetos a mostrar. Regularmente un objeto se crea mediante algo llamado POJO (Plain Old Java Object) y dicho POJO contiene todas las características del objeto. En este caso, el Objeto es cada curso y el curso contiene: ID, name y description. Ya abran notado que estos son los campos que se tienen para llenar cada elemento dentro del CardView, el Dataset de esta aplicación es un arreglo de objetos tipo curso. Este dataset es construido a partir de un JSON local llamado “cursos.json”, el parseo y manejo se encuentra en una clase llamada ReadLocalJSON por si tienen inquietud de como consumir un archivo JSON local.

    Código :

    public class Course {
    
        private Integer id;
        private String name;
        private String description;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    }
    


    Crear el Adapter no es tan complicado, lo primero que debemos hacer es crear una clase (en la aplicación se llama CoursesAdapter) que extienda de RecyclerView.Adapter<CoursesAdapter.ViewHolder> e Implementar los métodos requeridos. El constructor recibe dos parámetros, uno es el Dataset (Arreglo de objetos del tipo Curso) y el otro es el ItemLayout (es el layout que creamos con el CardView y describe cada curso)

    Código :

        private ArrayList<Course> courses;
        private int itemLayout;
    
    
        public  CoursesAdapter(ArrayList<Course> data,  int itemLayout){
            courses = data;
            this.itemLayout = itemLayout;
       }


    La clase interna ViewHolder que extiende de RecyclerView.ViewHolder contiene todos los llamados a los widgets contenidos en el ItemLayout (compuesto de un ImageView y 2 TextView), por lo que se garantiza que el llamado es solo una vez, haciendo que consuma menos recursos a nivel de batería y procesamiento. Anteriormente un ViewHolder era una buena práctica, ahora es algo obligatorio. Ademas se implementa un AdapterView.OnClickListener para que cada elemento en el listado tenga un evento OnClick, por el momento solo muestra un pequeño mensaje.

    Código :

     public static class ViewHolder extends RecyclerView.ViewHolder implements AdapterView.OnClickListener {
    
            public ImageView image;
            public TextView name;
            public TextView description;
    
            public ViewHolder(View itemView) {
                super(itemView);
    
                itemView.setOnClickListener(this);
    
                image = (ImageView) itemView.findViewById(R.id.image);
                name = (TextView) itemView.findViewById(R.id.name);
                description = (TextView) itemView.findViewById(R.id.description);
            }
    
            @Override
            public void onClick(View view) {
                Toast.makeText(view.getContext(),"OnItemClick :D", Toast.LENGTH_SHORT).show();
            }
    
        }



    El método onCreateViewHolder se encarga de inflar la vista del ItemLayout y el método onBindViewHolder es el encargado de pasar la información del Dataset a sus respectivos lugares en el ItemLayout. Ademas de recordarle al viewHolder el estado actual de los elementos del ItemLayout. Al final el método getItemCount nos permite conocer el tamaño o cantidad de elementos que contiene nuestro RecyclerView que es el mismo que el tamaño deldataset. Y listo, todo lo anterior en conjunto crea nuestro Adapter para poder usar nuestro RecyclerView.

    Código :

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(itemLayout, viewGroup, false);
            return new ViewHolder(v);
        }
    
        @Override
        public void onBindViewHolder(ViewHolder viewHolder, int position) {
    
            Course course = courses.get(position);
            viewHolder.name.setText(course.getName());
            viewHolder.description.setText(course.getDescription());
    
            switch (course.getId()){
                case 1:
    
                    viewHolder.image.setImageResource(R.drawable.disenio);
                    break;
    
                case 2:
    
                    viewHolder.image.setImageResource(R.drawable.android);
                    break;
    
                case 3:
                    viewHolder.image.setImageResource(R.drawable.swift);
                    break;
    
                case 4:
                    viewHolder.image.setImageResource(R.drawable.backend);
                    break;
            }
            viewHolder.itemView.setTag(course);
        }
    
    
        @Override
        public int getItemCount() {
            return courses.size();
        }


    Hasta este punto no hemos creado más que lo necesario para que el UI principal funcione (recordar que solo tenemos una Actividad con un Fragmento en ella). La vista del fragmento (cursos_fragment.xml) contiene un widget del tipo <android.support.v7.widget.RecyclerView> ademas de un <ImageButton> (que es el Float Button con la explicación más adelante). La clase onCreateView del Fragmento es la encargada de preparar nuestra vista, mientras que en onActivityCreated hacemos el llamado a todo aquello que usaremos para completar dicha vista, en este punto es donde hacemos el llamado a recyclerView, le seteamos el adapter que creamos (CoursesAdapter que para construirlo recibe un el dataset y la ItemLayout) y le indicamos al LayoutManager que sea un LinearLayoutManager (vista de lista).

    Código :

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android">
    
    
        <android.support.v7.widget.RecyclerView
            android:scrollbars="vertical"
            android:id="@+id/my_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    
        <ImageButton
            android:id="@+id/fab_1"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_width="@dimen/fab_size"
            android:layout_height="@dimen/fab_size"
            android:background="@drawable/riple"
            android:layout_marginBottom="16dp"
            android:layout_marginRight="16dp"
            android:stateListAnimator="@anim/anim"
            android:src="@drawable/reply"
            android:elevation="10dp" />
    
    </RelativeLayout>


    Código :

            
            ArrayList<Course> courses;
            ReadLocalJSON readLocalJSON = new ReadLocalJSON();
            courses = readLocalJSON.getCourses(getActivity());
    
            RecyclerView recyclerView = (RecyclerView) getActivity().findViewById(R.id.my_recycler_view);
            recyclerView.setHasFixedSize(true);
            recyclerView.setAdapter(new CoursesAdapter(courses, R.layout.row));
            recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            recyclerView.setItemAnimator(new DefaultItemAnimator());
    


    Creando un Float Button



    Lo último de este ejemplo es crear el Float Button, como podemos ver en la vista del fragmento se trata de un ImageButton (src="@drawable/reply" , que es la imagen de la flecha) con android:background="@drawable/riple", el ripple (riple.xml contenido en la carpeta drawable) es el que crea el un fondo background shape oval, siendo el color el declarado en el tema en un inicio: @color/acent_button, el tamaño del shape se encuentra declarado en cada uno de los archivos dimens.xml en las carpetas de values, contiene un android:elevation="10dp", ósea que va 10dp arriba del eje Z, lo cual, lo coloca por delante de cualquier cosa que muestre RecyclerView.

    Ademas (aunque no se pueda ver en este ejemplo) preparamos una animación de translationZ declarada en anim.xml en la carpeta anim, esta solo será visible cuando se pasa de una actividad a otra, por el momento no lo usaremos pero así es como se declara.

    Código :

    <ripple
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?android:colorControlHighlight">
        <item>
            <shape android:shape="oval">
                <solid android:color="@color/acent_button"/>
            </shape>
        </item>
    </ripple>


    Código :

    <resources>
        <!-- Default screen margins, per the Android Design guidelines. -->
        <dimen name="activity_horizontal_margin">16dp</dimen>
        <dimen name="activity_vertical_margin">16dp</dimen>
        <dimen name="spacing_xsmall">2dp</dimen>
        <dimen name="fab_size">56dp</dimen>
        <dimen name="button_elevation">4dp</dimen>
        <dimen name="button_press_elevation">4dp</dimen>
    </resources>
    


    Código :

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:state_enabled="true"
            android:state_pressed="true">
            <objectAnimator
                android:duration="500"
                android:propertyName="translationZ"
                android:valueFrom="@dimen/button_elevation"
                android:valueTo="@dimen/button_press_elevation"
                android:valueType="floatType" />
        </item>
        <item>
            <objectAnimator
                android:duration="500"
                android:propertyName="translationZ"
                android:valueFrom="@dimen/button_press_elevation"
                android:valueTo="@dimen/button_elevation"
                android:valueType="floatType" />
        </item>
    </selector>


    Ya por último en la clase del fragmento debemos declarar los Outline (Las sombras que hace ver el botón por estar mas arriba del eje Z).

    Código :

    int size = getResources().getDimensionPixelSize(R.dimen.fab_size);
            Outline outline = new Outline();
            outline.setOval(0, 0, size, size);
            ImageButton imageButton = (ImageButton) getActivity().findViewById(R.id.fab_1);
            imageButton.setOutline(outline);
            imageButton.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View view) {
                    Toast.makeText(getActivity(),"Mejorando.la: Aprende a crear el futuro de la Web",
                                                Toast.LENGTH_LONG).show();
                }
            });
        }

Seré profesor del Curso de programación de apps para Android de Mejorando.la. Por si quieres un contenido más a profundidad :D

Listo!, eso es a grosso modo una aplicación que usa Material Design ademas de los nuevos widgets, no duden en preguntar o demostrar alguna inquietud sobre el tema, quedo a sus ordenes por cualquier medio: @thespianartist

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate