Tutorial de base de datos Firebase Realtime para Android con RecyclerView

En esta pieza queremos ver varios ejemplos de RecyclerView y la base de datos Firebase Realtime. Básicamente cómo realizar varias operaciones CRUD como añadir, recuperar y mostrar en recyclerview.

¿Qué es la base de datos Firebase Realtime?

La base de datos en tiempo real Firebase es uno de los servicios proporcionados por la plataforma Firebase que es propiedad de Google.

Básicamente es lo que llamamos una Base de Datos BAAS, o una Base de Datos Backend como Servicio. Está alojado en la nube.

Definición de la Logística - Short

Definición de la Logística - Short
Definición de la Logística - Short

¿Por qué Firebase Realtime Database?

Se diferencia de muchas bases de datos que ya conoces en muchos aspectos. Estas formas son las que le dan a Firebase Realtime Database sus ventajas.

  1. Está alojada en la nube mientras que otras como SQLite y Realm están alojadas localmente. Esto hace que Firebase Realtime Database sea accesible para muchas aplicaciones. Las bases de datos como SQLite y Realm están localizadas en una sola aplicación. La base de datos en tiempo real de Firebase es accesible para muchas aplicaciones.
  2. Es en tiempo real. Esta es la mayor diferencia. Esto significa que guardas los datos y automáticamente los datos en todas las aplicaciones conectadas se actualizan al instante. Esto lo hace bastante aplicable a muchos tipos de apps como las de chat y mensajería, apps que requieren una sincronización instantánea.
  3. Almacena los datos en formato json a diferencia de las tablas en sqlite. Esto hace que Firebase Realtime Database sea bastante escalable.
  4. Tiene planes gratuitos y de pago. Este es el mejor caso, ya que puedes usarlo tanto para aprender como para fines comerciales.

¿Qué es RecyclerView?

RecyclerView es un adapterview androide que nos permite renderizar grandes conjuntos de datos de manera eficiente. Normalmente para renderizar listas de datos en android se necesita un adapterview y un adaptador. El adapterview es el widget de la lista y los ejemplos incluyen ListView, Gridview, Spinner y por supuesto RecyclerView.

Entonces el adaptador es normalmente responsable de conectar el adapterview a la fuente de datos. Y de hecho normalmente se pueden utilizar layouts personalizados para presentar un solo elemento de la lista. Ese layout también se infla dentro del adaptador.

Lee más sobre el RecyclerView aquí.

¿Por qué RecyclerView?

Bueno, hemos dicho que varios adapterviews pueden ser utilizados para la presentación de datos en android. Hay ListView, GridView, Spinner etc. ListView solía ser el más popular hasta la introducción de RecyclerView.

Hoy en día recyclerview es el adapterview más utilizado debido a su flexibilidad y rendimiento. RecyclerView se puede utilizar para construir casi cualquier tipo de vista, desde una vista de lista, a una vista de cuadrícula/escalonada, a una vista de tabla, a un calendario, etc.

Este hecho lo hace bastante especial y utilizable en muchos escenarios. Sin embargo, no es mucho más difícil que las otras vistas adaptadoras.

Herramientas utilizadas

Este ejemplo fue escrito con las siguientes herramientas:

  • Microsoft Windows 8.1 – Este es mi sistema operativo.
  • Android Studio – Este es mi IDE(Integerated Develpment Kit) por Jetbrains y Google.
  • Genymotion Emulator – Esto lo usamos para probar nuestras aplicaciones.
  • Lenguaje : Java – Java es el lenguaje de programación más popular.

1. Android Firebase => Simple RecyclerView – Guardar, recuperar y luego mostrar

[center]Android Firebase Realtime Database recyclerView Tutorial[/center]

Este es un tutorial de android firebase RecyclerView. Cómo guardar los datos a firebase, recuperar y luego mostrar que los datos en un simple Recyclerview. Sólo usamos un solo campo de datos.

Conceptos generales que se aprenden de este ejemplo.

Estos son algunos de los conceptos que puedes aprender de este tutorial:

  • Qué es Firebase y qué es RecyclerView y por qué usarlos.
  • Cómo guardar los datos de edittext en la base de datos de Google Firebase en tiempo real.
  • Cómo obtener o recuperar o leer datos de la base de datos Firebase adjuntando eventos a una instancia DatabaseReference y luego rellenando un arraylist de java
  • Cómo vincular los datos recuperados a una instancia de la subclase RecyclerView.Adapter.
  • Cómo crear y operar con la base de datos en Firebase.
  • Aplicaciones de ejemplo de Firebase con recyclerview.
  • Sincronización de la base de datos Firebase

Conceptos específicos que aprenderás

  • Cómo utilizar la referencia de la base de datos Firebase.
  • Cómo añadir un hijo a la referencia de la base de datos Firebase

Demo

Aquí está la demo del proyecto para este tutorial:

Instalación y Configuración

(a). Crear Proyecto de Actividad Básica
  1. Primero cree un nuevo proyecto en android studio.
(b). Crear Firebase y descargar el archivo de configuración

Dirígete a la consola de Firebase, crea una aplicación Firebase, registra el id de tu aplicación y descarga el archivo google-services.json. Añádelo a la carpeta de tu app.

(c). Especifica la URL del repositorio de Maven

Dirígete al nivel del proyecto (carpeta del proyecto) build.gradle y

  1. Añade el classpath de los servicios de Google como se indica a continuación
  2. Añade la URL del repositorio de Maven

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Esto nos permitirá obtener nuestro Firebase desde maven.google com. Firebase es una librería de terceros y hay que descargarla para poder usarla en nuestro proyecto.

(d). Añadir las dependencias de Firebase

Añádelas en tu nivel de aplicación (carpeta app) build.gradle necesitamos añadir varias dependencias. Hemos añadido librerías de soporte como appcompat, design y cardview. AppCompat nos dará AppCompatActivity, la clase de la que derivará nuestra MainActivity. Los añadimos utilizando la sentencia implementation.

El soporte design nos dará el recyclerveiew que es nuestro widget de lista. Es lo que vamos a poblar con los datos que consultemos desde nuestra Firebase. El cardview por otro lado nos permitirá trabajar con cardviews como nuestras vistas de elementos. El recyclerview estará compuesto por cardviews.

Luego hemos añadido el Core de Firebase así como la Base de Datos de Firebase. Firebase remember es una plataforma mientras que Firebase Database es la base de datos donde almacenamos nuestros datos. Puedes utilizar versiones posteriores. Sin embargo no olvides aplicar los servicios de google como hemos hecho nosotros.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:appcompat-v7:23.3.0'
    implementation 'com.android.support:design:23.3.0'
    implementation 'com.android.support:cardview-v7:23.3.0'

    implementation 'com.google.firebase:firebase-core:11.8.0'
    implementation 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Asegúrate de aplicar el plugin apply: 'com.google.gms.google-services' como en el caso anterior.

2. Nuestro código Java

Escribimos este ejemplo utilizando el lenguaje de programación Java. Así que desacoplaremos varias partes de nuestra aplicación en varias clases.

(a). Nuestra Clase Modelo
  • Es nuestra clase Objeto de Datos
  • Debe tener un constructor vacío.
  • Puede crear, pasar datos y utilizar otros constructores

Como clase modelo o data objexct representa básicamente una clase que modelará nuestros datos. Cuando se trabaja con cualquier forma de datos, siempre es una buena idea representar los datos en una clase concreta simple. El objeto de esa clase puede entonces ser consultado según sea necesario. Normalmente este tipo de clases tienen lo que llamamos métodos de acceso. Estos métodos son siempre públicos, por lo que proporcionan una forma de exponer las propiedades de la clase, que son siempre privadas.

En nuestro caso, hemos creado una clase llamada Spacecraft. Esa clase, tendrá una sola propiedad, sólo un nombre para mantener el nombre de esa nave espacial. Luego dotamos a nuestra clase de un constructor público por defecto. Esta es una característica que normalmente necesitan los motores de bases de datos que se basan en la lectura del objeto de datos para generar automáticamente el esquema de la base de datos. La base de datos Firebase definitivamente hace eso al igual que Realm, una base de datos local para java y android.

Luego proveemos a nuestra clase con los métodos de acceso getName y setName.

package com.tutorials.hp.firebasesimplerecyclerview.m_Model;

public class Spacecraft {

    String name;

    //EMPTY CONSTR
    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
(b). Nuestra clase FirebaseHelper
  • Básicamente, nuestra clase CRUD.
  • Aquí realizamos lecturas y escrituras en la base de datos Firebase.
  • Para persistir los datos usamos setValue().
  • Antes de llamar al método setValue(), llamamos a push() para asegurarnos de que añadimos los datos a la base de datos, no los reemplazamos.
  • Llenamos un simple arraylist.

Hemos creado esta clase, FirebaseHelper para permitirnos guardar, así como consultar o leer datos de Firebase. Comenzamos definiendo el paquete para alojar nuestra clase. Luego añadimos nuestras importaciones incluyendo varias clases de com.google.firebase.database.

Hemos definido varios campos de instancia incluyendo:

  1. DatabaseReference — La referencia de nuestra base de datos.
  2. Valor booleano – para determinar si hemos guardado con éxito o no.
  3. ArrayList – Para mantener nuestros datos obtenidos de Firebase.

Comenzamos recibiendo una referencia de base de datos a través del constructor. Luego asignamos la referencia de la base de datos al campo de instancia local que habíamos mantenido.

Guardando los datos en FirebaseDatabase

A continuación definimos un método para guardar los datos en la base de datos Firebase. Ese método recibirá un objeto Spacecraft como parámetro. Dado que estamos recibiendo el objeto Spacecraft desde el mundo exterior, sería ideal comprobar primero si es nulo.

Para guardar los datos en Firebase

    db.child("Spacecraft").push().setValue(spacecraft);

En este caso db es nuestra DatabaseReference. Obtenemos su nodo hijo a través del método child(). Luego pasamos el nombre de nuestra "tabla". Luego usamos el método push() para enviar los datos a Firebase. Sin embargo, tenemos que establecer el valor que estamos empujando. Usamos el método setValue para establecer nuestro objeto spacecraft. Y así es como guardamos los datos en nuestra base de datos Firebase. Fíjate que hemos utilizado un bloque try catch para atrapar una DatabaseException.

**Recuperación de datos de la base de datos Firebase

Recibiremos los datos de la Base de Datos Firebase en tiempo real y rellenaremos un ArrayList. Más tarde esa ArrayList se utilizará como fuente de datos para nuestro adaptador recyclerview.

Para leer los datos de Firebase, necesitamos adjuntar un ChildEventListener a nuestra referencia de base de datos. Esto escuchará los cambios en los nodos de datos. Por ejemplo, cuando un nodo hijo es añadido, modificado, eliminado o cancelado, obtenemos métodos de devolución de llamadas que contienen nuestra instantánea de datos. Entonces podemos leer los datos de esas instantáneas de datos.

Entonces desde cada iteración se puede invocar el método getValue del hijo de la instantánea de datos para obtener el objeto. Leer datos de un objeto DataSnapshot es fácil. Simplemente se hace un bucle a través de sus hijos:

 for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            String name=ds.getValue(Spacecraft.class).getName();
            spacecrafts.add(name);
        }

Aquí está el código completo:

package com.tutorials.hp.firebasesimplerecyclerview.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebasesimplerecyclerview.m_Model.Spacecraft;

import java.util.ArrayList;

public class FirebaseHelper {

    DatabaseReference db;
    Boolean saved=null;
    ArrayList<String> spacecrafts=new ArrayList<>();

    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }

    //SAVE
    public Boolean save(Spacecraft spacecraft)
    {
        if(spacecraft==null)
        {
            saved=false;
        }else {

            try
            {
                db.child("Spacecraft").push().setValue(spacecraft);
                saved=true;
            }catch (DatabaseException e)
            {
                e.printStackTrace();
                saved=false;
            }

        }

        return saved;
    }

    //READ
    public ArrayList<String> retrieve()
    {
        db.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

        return spacecrafts;
    }

    private void fetchData(DataSnapshot dataSnapshot)
    {
        spacecrafts.clear();
        for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            String name=ds.getValue(Spacecraft.class).getName();
            spacecrafts.add(name);
        }
    }

}
(c). Nuestra clase MyViewHolder
  • Sí, es nuestra clase viewholder.
  • Mantiene las vistas para su uso, listas para ser recicladas

package com.tutorials.hp.firebasesimplerecyclerview.m_UI;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

import com.tutorials.hp.firebasesimplerecyclerview.R;

public class MyViewHolder extends RecyclerView.ViewHolder  {

    TextView nameTxt;

    public MyViewHolder(View itemView) {
        super(itemView);

        nameTxt=(TextView) itemView.findViewById(R.id.nameTxt);
    }
}

Ese MyViewHolder es nuestra clase ViewHolder. Estos siempre son necesarios para el reciclaje de las vistas por el recyclerview. Sin embargo, para convertir una clase en un viewholder de recyclerview tenemos que derivar de la clase Recyclerview.ViewHolder como has visto arriba. Hemos empezado imprimiendo varias clases incluyendo la propia RecyclerView.

En nuestra clase hemos mantenido un TextView llamado nombreTxt. Luego nuestro constructor MyViewHolder ha tomado un objeto View. Ese objeto View se ha pasado a la superclase que es el Recyclerview.ViewHolder.

Luego hemos referenciado el nombreTxt de su especificación de diseño.

9. Nuestra clase MyAdapter
  • Responsable de la inflación del layout.
  • También para la vinculación de datos a las vistas.

package com.tutorials.hp.firebasesimplerecyclerview.m_UI;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tutorials.hp.firebasesimplerecyclerview.R;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

    Context c;
    ArrayList<String> spacecrafts;

    public MyAdapter(Context c, ArrayList<String> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v=LayoutInflater.from(c).inflate(R.layout.model,parent,false);
        return new MyViewHolder(v);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.nameTxt.setText(spacecrafts.get(position));

    }

    @Override
    public int getItemCount() {
        return spacecrafts.size();
    }
}

Los adaptadores son importantes en la forma en que android trabaja con la recolección de datos. Los dispositivos móviles, ya sea HTC, Samsung, F7, Apple iOS, Infinix, etc, todos ellos pesadamente aplicaciones que necesitan para hacer las listas de datos. Eso es sólo por la naturaleza de los dispositivos móviles. La pantalla es siempre pequeña y por lo tanto es conveniente mostrar elementos que puedan ser desplazados.

Y RecyclerView es el adapterview número uno para mostrar grandes conjuntos de datos. Estos conjuntos de datos pueden venir de la nube como Firebase. Y de hecho nuestros datos en este caso vienen de la base de datos Firebase Realtime. Así que hemos poblado un ArrayList hasta ahora con los datos que ya hemos recogido. Ahora es el momento de enlazar esos datos. Sin embargo eso necesita un Adapter.

Adaptadores:

  1. Nos permiten enlazar los datos a nuestros adapterviews.
  2. Nos ayudan a inflar los layouts personalizados en las vistas para que diseñemos adapterviews personalizados.

Un adaptador recyclerview se hace derivando de RecyclerView.Adapter<MyViewHolder>. El parámetro genérico es el ViewHolder. Derivar de esa clase nos obligará a sobrescribir tres métodos:

  1. getItemCount – Para devolver el número de elementos a renderizar en el recyclerview.
    1. onCreateViewHolder – Aquí es donde se produce el inflado. UsamosLayoutInflater para el inflado.
    1. onBindViewHolder – Aquí es donde vinculamos los datos a los widgets que definimos en la clase ViewHolder.

Mientras tanto nuestro constructor ha tomado un objeto Context así como el arraylist de nuestros datos.

(d). Nuestra MainActivity
  • Actividad de lanzamiento.
  • Hace referencia al RecyclerView y establece su layoutManager así como su adaptador.
  • Muestra el diálogo de entrada al hacer clic en el botón FAB.
  • Establece nuestro Firebase’s inicializando el DatabaseReference.

package com.tutorials.hp.firebasesimplerecyclerview;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebasesimplerecyclerview.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebasesimplerecyclerview.m_Model.Spacecraft;
import com.tutorials.hp.firebasesimplerecyclerview.m_UI.MyAdapter;

public class MainActivity extends AppCompatActivity {

    DatabaseReference db;
    FirebaseHelper helper;
    RecyclerView rv;
    EditText nameEditTxt;
    MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //SETUP RV
        rv= (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));

        //SETUP FB
        db=FirebaseDatabase.getInstance().getReference();
        helper=new FirebaseHelper(db);

        //ADAPTER
        adapter=new MyAdapter(this,helper.retrieve());
        rv.setAdapter(adapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                  displayInputDialog();
            }
        });
    }

    private void displayInputDialog()
    {
        Dialog d=new Dialog(this);
        d.setTitle("Save To Firebase");
        d.setContentView(R.layout.input_dialog);

        nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
        Button saveBtn= (Button) d.findViewById(R.id.saveBtn);

        //SAVE
        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //GET DATA
                String name=nameEditTxt.getText().toString();

                //SET DATA
                Spacecraft s=new Spacecraft();
                s.setName(name);

                //VALIDATE
                if(name.length()>0 && name != null)
                {
                    if(helper.save(s))
                    {
                        nameEditTxt.setText("");
                         adapter=new MyAdapter(MainActivity.this,helper.retrieve());
                        rv.setAdapter(adapter);
                    }
                }else
                {
                    Toast.makeText(MainActivity.this, "Name Cannot Be Empty", Toast.LENGTH_SHORT).show();
                }
            }
        });

        d.show();
    }

}

11. Nuestros Layouts

(a). activity_main.xml

Este es nuestro diseño principal activity.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_fitsSystemWindows="true"
    tools_context="com.tutorials.hp.firebasesimplerecyclerview.MainActivity">

    <android.support.design.widget.AppBarLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android_id="@+id/toolbar"
            android_layout_width="match_parent"
            android_layout_height="?attr/actionBarSize"
            android_background="?attr/colorPrimary"
            app_popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android_id="@+id/fab"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_gravity="bottom|end"
        android_layout_margin="@dimen/fab_margin"
        android_src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(b). content_main.xml

Aquí es donde añadimos nuestro adapterview en este caso un recyclerview.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_paddingBottom="@dimen/activity_vertical_margin"
    android_paddingLeft="@dimen/activity_horizontal_margin"
    android_paddingRight="@dimen/activity_horizontal_margin"
    android_paddingTop="@dimen/activity_vertical_margin"
    app_layout_behavior="@string/appbar_scrolling_view_behavior"
    tools_context="com.tutorials.hp.firebasesimplerecyclerview.MainActivity"
    tools_showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android_id="@+id/rv"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
         />
</RelativeLayout>
(c). input_dialog.xml
  • define el diseño de nuestros diálogos de entrada

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android_orientation="vertical" android_layout_width="match_parent"
    android_layout_height="match_parent">

    <LinearLayout
        android_layout_width="fill_parent"
        android_layout_height="match_parent"
        android_layout_marginTop="?attr/actionBarSize"
        android_orientation="vertical"
        android_paddingLeft="15dp"
        android_paddingRight="15dp"
        android_paddingTop="10dp">

        <android.support.design.widget.TextInputLayout
            android_id="@+id/nameLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/nameEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <Button android_id="@+id/saveBtn"
            android_layout_width="fill_parent"
            android_layout_height="wrap_content"
            android_text="Save"
            android_clickable="true"
            android_background="@color/colorAccent"
            android_layout_marginTop="10dp"
            android_textColor="@android:color/white"/>

    </LinearLayout>

</LinearLayout>
(d). model.xml

Este es nuestro modelo de fila RecyclerView. Este layout será inflado en la clase adaptadora.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    android_orientation="horizontal" android_layout_width="match_parent"

    android_layout_margin="10dp"
    card_view_cardCornerRadius="5dp"
    card_view_cardElevation="5dp"
    android_layout_height="200dp">

        <LinearLayout
            android_orientation="vertical"
            android_layout_width="match_parent"
            android_layout_height="match_parent">

            <TextView
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Name"
                android_id="@+id/nameTxt"
                android_padding="10dp"
                android_textColor="@color/colorAccent"
                android_textStyle="bold"
                android_layout_alignParentLeft="true"
                />

    </LinearLayout>

</android.support.v7.widget.CardView>
12. AndroidManifest.xml
  • Recuerda añadir el permiso para internet en tu archivo de manifiesto.

<usa-permiso android_name="android.permission.INTERNET"/>

Descargar

Navegar
Download

2. Android Firebase – RecicladorVer múltiples campos

Tutorial de RecyclerView para Android Firebase_ Este es un tutorial de RecyclerView para Android Firebase. Como guardar datos en firebase, recuperar y luego mostrar esos datos en un RecyclerView personalizado.

Esta vez utilizamos múltiples campos en lugar de un solo campo como lo hicimos en el ejemplo anterior.

1. Configuración

(a). Crear un proyecto de actividad básica
  1. Primero cree un nuevo proyecto en android studio. Ve a Archivo –> Nuevo Proyecto.
(b).Crear Firebase y descargar el archivo de configuración

Dirígete a la consola de Firebase, crea una aplicación Firebase, registra el id de tu aplicación y descarga el archivo google-services.json. Añádelo a la carpeta de tu app.

(c). Especificar la URL del repositorio Maven

Dirígete al nivel del proyecto (carpeta del proyecto) build.gradle y

  1. Añade el classpath de los servicios de Google como se indica a continuación
  2. Añade la url del repositorio maven

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
(d). Añade las dependencias de Firebase

Añádelas en tu nivel de aplicación (carpeta de la aplicación) build.gradle, entonces

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'

    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Asegúrate de aplicar el plugin apply: 'com.google.gms.google-services' como arriba.

(e). AndroidManifest
  • Recuerda añadir el permiso para internet en tu archivo de manifiesto.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="com.tutorials.hp.firebaserecyclermulti_items">

    <uses-permission android_name="android.permission.INTERNET"/>
    ....
</manifest>

2. Clases

(a). Nuestra Clase Modelo
  • Es nuestra clase Objeto de Datos
  • Debe tener un constructor vacío.
  • Puede crear, pasar datos y utilizar otros constructores

package com.tutorials.hp.firebaserecyclermulti_items.m_Model;

/*
 * 1. OUR MODEL CLASS
 */
public class Spacecraft {
    String name,propellant,description;

    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPropellant() {
        return propellant;
    }

    public void setPropellant(String propellant) {
        this.propellant = propellant;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
(b). Nuestra clase FirebaseHelper
  • Básicamente, nuestra clase CRUD.
  • Aquí realizamos lecturas y escrituras en la base de datos Firebase.
  • Para persistir los datos usamos setValue().
  • Antes de llamar al método setValue(), llamamos a push() para asegurarnos de que añadimos datos a la base de datos, no los reemplazamos.
  • Llenamos un arraylist con objetos del modelo.

package com.tutorials.hp.firebaserecyclermulti_items.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebaserecyclermulti_items.m_Model.Spacecraft;

import java.util.ArrayList;

/*
 * 1. RECEIVE DB REFERENCE
 * 2. SAVE
 * 3. RETRIEVE
 * 4. RETURN ARRAYLIST
 */
public class FirebaseHelper {
    DatabaseReference db;
    Boolean saved=null;
    ArrayList<Spacecraft> spacecrafts=new ArrayList<>();

    /*
     PASS DATABASE REFRENCE
     */
    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }

    //WRITE IF NOT NULL
    public Boolean save(Spacecraft spacecraft)
    {
        if(spacecraft==null)
        {
            saved=false;

        }else
        {
            try
            {
                db.child("Spacecraft").push().setValue(spacecraft);
                saved=true;

            }catch (DatabaseException e)
            {
                e.printStackTrace();
                saved=false;
            }
        }

        return saved;
    }

    //IMPLEMENT FETCH DATA AND FILL ARRAYLIST
    private void fetchData(DataSnapshot dataSnapshot)
    {
        spacecrafts.clear();

        for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            Spacecraft spacecraft=ds.getValue(Spacecraft.class);
            spacecrafts.add(spacecraft);
        }
    }

    //READ BY HOOKING ONTO DATABASE OPERATION CALLBACKS
    public ArrayList<Spacecraft> retrieve()
    {
        db.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

        return spacecrafts;
    }

}
(c). Nuestra clase ViewHolder
  • Guarda las vistas para que las podamos reciclar.
  • Subclases RecyclerView.ViewHolder

package com.tutorials.hp.firebaserecyclermulti_items.m_UI;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.tutorials.hp.firebaserecyclermulti_items.R;

/*
 * 1. HOLD VIEWS
 */
public class MyViewHolder extends RecyclerView.ViewHolder {

    TextView nameTxt,propTxt,descTxt;

    public MyViewHolder(View itemView) {
        super(itemView);

        nameTxt=(TextView) itemView.findViewById(R.id.nameTxt);
        propTxt=(TextView) itemView.findViewById(R.id.propellantTxt);
        descTxt=(TextView) itemView.findViewById(R.id.descTxt);
    }
}

9. Nuestra clase MyAdapter

  • Responsable de la Inflación del Layout.
  • También para la vinculación de datos a las vistas.
  • Esta clase subclase RecyclerView.Adapter

package com.tutorials.hp.firebaserecyclermulti_items.m_UI;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tutorials.hp.firebaserecyclermulti_items.R;
import com.tutorials.hp.firebaserecyclermulti_items.m_Model.Spacecraft;

import java.util.ArrayList;

/
 * 1. LAYOUT INFLATION
 * 2. RECEIVE SPACECRAFTS
 * 3. PERFORM BINDING
 */
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    Context c;
    ArrayList<Spacecraft> spacecrafts;

    public MyAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v=LayoutInflater.from(c).inflate(R.layout.model,parent,false);
        return new MyViewHolder(v);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.nameTxt.setText(spacecrafts.get(position).getName());
        holder.propTxt.setText(spacecrafts.get(position).getPropellant());
        holder.descTxt.setText(spacecrafts.get(position).getDescription());

    }

    @Override
    public int getItemCount() {
        return spacecrafts.size();
    }
}
(d). Nuestra MainActivity
  • Actividad de lanzamiento.
  • Hacer referencia a RecyclerView y establecer su LayoutManager
  • Establece su adaptador.
  • Muestra el diálogo de entrada al hacer clic en el botón FAB.
  • Establece nuestro Firebase’s inicializando el DatabaseReference.

package com.tutorials.hp.firebaserecyclermulti_items;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebaserecyclermulti_items.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebaserecyclermulti_items.m_Model.Spacecraft;
import com.tutorials.hp.firebaserecyclermulti_items.m_UI.MyAdapter;
/*
1.INITIALIZE FIREBASE DB
2.INITIALIZE UI
3.DATA*/
public class MainActivity extends AppCompatActivity {

    DatabaseReference db;
    FirebaseHelper helper;
    MyAdapter adapter;
    RecyclerView rv;
    EditText nameEditTxt,propTxt,descTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //INITIALIZE RV
        rv= (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));

        //INITIALIZE FB
        db= FirebaseDatabase.getInstance().getReference();

        helper=new FirebaseHelper(db);

        //ADAPTER
        adapter=new MyAdapter(this,helper.retrieve());
        rv.setAdapter(adapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                displayInputDialog();
            }
        });
    }

    //DISPLAY INPUT DIALOG
    private void displayInputDialog()
    {
        //CREATE DIALOG
        Dialog d=new Dialog(this);
        d.setTitle("Save To Firebase");
        d.setContentView(R.layout.input_dialog);

        nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
        propTxt= (EditText) d.findViewById(R.id.propellantEditText);
        descTxt= (EditText) d.findViewById(R.id.descEditText);
        Button saveBtn= (Button) d.findViewById(R.id.saveBtn);

        //SAVE
        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //GET DATA
                String name=nameEditTxt.getText().toString();
                String propellant=propTxt.getText().toString();
                String desc=descTxt.getText().toString();

                //SET DATA
                Spacecraft s=new Spacecraft();
                s.setName(name);
                s.setPropellant(propellant);
                s.setDescription(desc);

                //SAVE
                if(name != null && name.length()>0)
                {
                    if(helper.save(s))
                    {
                        nameEditTxt.setText("");
                        propTxt.setText("");
                        descTxt.setText("");

                        adapter=new MyAdapter(MainActivity.this,helper.retrieve());
                        rv.setAdapter(adapter);
                    }
                }else
                {
                    Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
                }

            }
        });

        d.show();
    }
}

3. Nuestros Layouts

(a). InputDialog.xml
  • define el diseño de nuestros diálogos de entrada

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android_orientation="vertical" android_layout_width="match_parent"
    android_layout_height="match_parent">

    <LinearLayout
        android_layout_width="fill_parent"
        android_layout_height="match_parent"
        android_layout_marginTop="?attr/actionBarSize"
        android_orientation="vertical"
        android_paddingLeft="15dp"
        android_paddingRight="15dp"
        android_paddingTop="50dp">

        <android.support.design.widget.TextInputLayout
            android_id="@+id/nameLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/nameEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android_id="@+id/propLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/propellantEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Propellant" />

        <android.support.design.widget.TextInputLayout
            android_id="@+id/descLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/descEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Description" />
        </android.support.design.widget.TextInputLayout>

        </android.support.design.widget.TextInputLayout>

        <Button android_id="@+id/saveBtn"
            android_layout_width="fill_parent"
            android_layout_height="wrap_content"
            android_text="Save"
            android_clickable="true"
            android_background="@color/colorAccent"
            android_layout_marginTop="40dp"
            android_textColor="@android:color/white"/>

    </LinearLayout>

</LinearLayout>
(b). Model.xml
  • Cómo debe aparecer cada elemento de la vista.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    android_orientation="horizontal" android_layout_width="match_parent"

    android_layout_margin="10dp"
    card_view_cardCornerRadius="5dp"
    card_view_cardElevation="5dp"
    android_layout_height="200dp">

        <LinearLayout
            android_orientation="vertical"
            android_layout_width="match_parent"
            android_layout_height="match_parent">

            <TextView
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Name"
                android_id="@+id/nameTxt"
                android_padding="10dp"
                android_textColor="@color/colorAccent"
                android_textStyle="bold"
                android_layout_alignParentLeft="true"
                />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Description....................."
                android_lines="3"
                android_id="@+id/descTxt"
                android_padding="10dp"
                android_layout_alignParentLeft="true"
                />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceMedium"
                android_text="Propellant"
                android_textStyle="italic"
                android_id="@+id/propellantTxt" />

    </LinearLayout>

</android.support.v7.widget.CardView>

4. Descargar

Navegar
Descargar

3. Android Firebase – RecyclerView Master Detail \ ~ [Abrir Actividad]

Hola, bienvenido a nuestro Android Firebase RecyclerView Maestro detalle tutorial.

Este es un tutorial de android firebase recyclerview. Cómo guardar los datos a firebase, recuperar y luego mostrar que los datos en un gridview personalizado.

  • Guardar los datos de edittext a la base de datos de google firebase.
  • Recuperar los datos adjuntando eventos a una instancia de DatabaseReference.
  • Vincular los datos a un gridview csutom usando una subclase de BaseAdapter.
  • Manejar los itemClicks del GridView.
  • Abrir una nueva actividad cuando se hace clic en un elemento de la cuadrícula.
  • Pasar los datos a esa nueva actividad

¿Qué es la base de datos Firebase Realtime?

La base de datos en tiempo real de Firebase es una solución de base de datos como servicio alojada en la nube que nos da la plataforma para construir aplicaciones ricas.Normalmente estamos acostumbrados a hacer peticiones HTTP para leer o escribir datos contra nuestros servidores.Pero no en Firebase.Utiliza una tecnología de sincronización que le permite ser en tiempo real, pero todavía performante.

¿Principales características?

  • Es en tiempo real.
  • Independiente de la plataforma.
  • Fácil control de acceso.
  • Es una solución NoSQL y está fuertemente optimizada para el rendimiento.
  • Tiene capacidad offline.
  • Es fácil de usar.

Video Tutorial Para más explicaciones por favor revise nuestro video tutorial abajo.

Configuración

(a) Crear un proyecto de actividad básica
  1. Primero cree un nuevo proyecto en android studio. Vaya a Archivo –> Nuevo Proyecto.
(b). Crear Firebase y descargar el archivo de configuración

Dirígete a la consola de Firebase, crea una aplicación Firebase, registra el id de tu aplicación y descarga el archivo google-services.json. Añádelo a la carpeta de tu app.

(c). Especifica la URL del repositorio de Maven

Dirígete al nivel del proyecto (carpeta del proyecto) build.gradle y

  1. Añade el classpath de los servicios de Google como se indica a continuación
  2. Añade la url del repositorio maven

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.google.gms:google-services:3.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com" // Google's Maven repository
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
(d). Añade las dependencias de Firebase

Añádelas en el build.gradle del nivel de tu aplicación (carpeta de la aplicación), entonces

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'

    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
}
apply plugin: 'com.google.gms.google-services'

Asegúrate de aplicar el plugin apply: 'com.google.gms.google-services' como arriba.

(e). AndroidManifest.xml
  • Recuerda añadir el permiso para internet en tu archivo de manifiesto.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="com.tutorials.hp.firebaserecyclermdetail">

    <uses-permission android_name="android.permission.INTERNET"/>

    <application
        android_allowBackup="true"
        android_icon="@mipmap/ic_launcher"
        android_label="@string/app_name"
        android_supportsRtl="true"
        android_theme="@style/AppTheme">
        <activity
            android_name=".MainActivity"
            android_label="@string/app_name"
            android_theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android_name="android.intent.action.MAIN" />

                <category android_name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android_name=".DetailActivity"
            android_label="Detail View"
            android_theme="@style/AppTheme.NoActionBar">
        </activity>
    </application>

</manifest>

Clases Java

(a). Spacecraft.java
  • Es nuestra clase de objeto de datos
  • Debe tener un constructor vacío.
  • Puede crear, pasar datos y utilizar otros constructores

package com.tutorials.hp.firebaserecyclermdetail.m_Model;

/*
 * 1. OUR MODEL CLASS
 */
public class Spacecraft {

    String name,propellant,description;

    public Spacecraft() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPropellant() {
        return propellant;
    }

    public void setPropellant(String propellant) {
        this.propellant = propellant;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
(b). FirebaseHelper.java
  • Básicamente, nuestra clase CRUD.
  • Aquí realizamos lecturas y escrituras en la base de datos Firebase.
  • Para persistir los datos usamos setValue().
  • Antes de llamar al método setValue(), llamamos a push() para asegurarnos de que añadimos los datos a la base de datos, no los reemplazamos.
  • Llenamos un arraylist con objetos de naves espaciales.

package com.tutorials.hp.firebaserecyclermdetail.m_FireBase;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.tutorials.hp.firebaserecyclermdetail.m_Model.Spacecraft;

import java.util.ArrayList;

/*
 * 1.SAVE DATA TO FIREBASE
 * 2. RETRIEVE
 * 3.RETURN AN ARRAYLIST
 */
public class FirebaseHelper {

    DatabaseReference db;
    Boolean saved=null;
    ArrayList<Spacecraft> spacecrafts=new ArrayList<>();

    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }

    //WRITE IF NOT NULL
    public Boolean save(Spacecraft spacecraft)
    {
        if(spacecraft==null)
        {
            saved=false;
        }else
        {
            try
            {
                db.child("Spacecraft").push().setValue(spacecraft);
                saved=true;

            }catch (DatabaseException e)
            {
                e.printStackTrace();
                saved=false;
            }
        }

        return saved;
    }

    //IMPLEMENT FETCH DATA AND FILL ARRAYLIST
    private void fetchData(DataSnapshot dataSnapshot)
    {
        spacecrafts.clear();

        for (DataSnapshot ds : dataSnapshot.getChildren())
        {
            Spacecraft spacecraft=ds.getValue(Spacecraft.class);
            spacecrafts.add(spacecraft);
        }
    }

    //READ THEN RETURN ARRAYLIST
    public ArrayList<Spacecraft> retrieve() {
        db.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
        return spacecrafts;
    }
}
(c). MyViewHolder.java
  • Es nuestra clase viewholder
  • Sostiene las vistas que se mostrarán en nuestro RecyclerView

package com.tutorials.hp.firebaserecyclermdetail.m_UI;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

import com.tutorials.hp.firebaserecyclermdetail.R;

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    TextView nameTxt,propTxt,descTxt;
    ItemClickListener itemClickListener;

    public MyViewHolder(View itemView) {
        super(itemView);

        nameTxt= (TextView) itemView.findViewById(R.id.nameTxt);
        propTxt= (TextView) itemView.findViewById(R.id.propellantTxt);
        descTxt= (TextView) itemView.findViewById(R.id.descTxt);

        itemView.setOnClickListener(this);
    }

    public void setItemClickListener(ItemClickListener itemClickListener)
    {
        this.itemClickListener=itemClickListener;
    }

    @Override
    public void onClick(View view) {
        this.itemClickListener.onItemClick(this.getLayoutPosition());
    }
}
(d). MyAdapter.java
  • Responsable del Layout Inflation.
  • También para la vinculación de datos a las vistas.
  • Luego abre una nueva actividad y le pasa los datos a través de android.Content.Intent.

package com.tutorials.hp.firebaserecyclermdetail.m_UI;

import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tutorials.hp.firebaserecyclermdetail.DetailActivity;
import com.tutorials.hp.firebaserecyclermdetail.R;
import com.tutorials.hp.firebaserecyclermdetail.m_Model.Spacecraft;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

    Context c;
    ArrayList<Spacecraft> spacecrafts;

    public MyAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v=LayoutInflater.from(c).inflate(R.layout.model,parent,false);
        return new MyViewHolder(v);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        final  Spacecraft s=spacecrafts.get(position);

        holder.nameTxt.setText(s.getName());
        holder.propTxt.setText(s.getPropellant());
        holder.descTxt.setText(s.getDescription());

        holder.setItemClickListener(new ItemClickListener() {
            @Override
            public void onItemClick(int pos) {
                //OPEN DETAI ACTIVITY
                openDetailActivity(s.getName(),s.getDescription(),s.getPropellant());
            }
        });
    }

    @Override
    public int getItemCount() {
        return spacecrafts.size();
    }

    //OPEN DETAIL ACTIVITY
    private void openDetailActivity(String...details)
    {
        Intent i=new Intent(c,DetailActivity.class);

        i.putExtra("NAME_KEY",details[0]);
        i.putExtra("DESC_KEY",details[1]);
        i.putExtra("PROP_KEY",details[2]);

        c.startActivity(i);
    }
}
(e). ItemClickListener.java
  • Define para nosotros la firma de nuestro método onItemClick().

package com.tutorials.hp.firebaserecyclermdetail.m_UI;

public interface ItemClickListener {

    void onItemClick(int pos);
}

12. MainActivity.java

  • Actividad de lanzamiento.
  • Hace referencia a RecyclerView, establece su adaptador.
  • Muestra el diálogo de entrada al hacer clic en el botón FAB.
  • Establece nuestro Firebase’s inicializando el DatabaseReference.

package com.tutorials.hp.firebaserecyclermdetail;

import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.tutorials.hp.firebaserecyclermdetail.m_FireBase.FirebaseHelper;
import com.tutorials.hp.firebaserecyclermdetail.m_Model.Spacecraft;
import com.tutorials.hp.firebaserecyclermdetail.m_UI.MyAdapter;

/*
1.INITIALIZE FIREBASE DB
2.INITIALIZE UI
3.DATA INPUT
 */
public class MainActivity extends AppCompatActivity {
    DatabaseReference db;
    FirebaseHelper helper;
    MyAdapter adapter;
    RecyclerView rv;
    EditText nameEditTxt,propTxt,descTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //SETUP RECYCLER
        rv = (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));

        //INITIALIZE FIREBASE DB
        db= FirebaseDatabase.getInstance().getReference();
        helper=new FirebaseHelper(db);

        //ADAPTER
        adapter=new MyAdapter(this,helper.retrieve());
        rv.setAdapter(adapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                displayInputDialog();
            }
        });
    }

    //DISPLAY INPUT DIALOG
    private void displayInputDialog()
    {
        Dialog d=new Dialog(this);
        d.setTitle("Save To Firebase");
        d.setContentView(R.layout.input_dialog);

        nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
        propTxt= (EditText) d.findViewById(R.id.propellantEditText);
        descTxt= (EditText) d.findViewById(R.id.descEditText);
        Button saveBtn= (Button) d.findViewById(R.id.saveBtn);

        //SAVE
        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //GET DATA
                String name=nameEditTxt.getText().toString();
                String propellant=propTxt.getText().toString();
                String desc=descTxt.getText().toString();

                //SET DATA
                Spacecraft s=new Spacecraft();
                s.setName(name);
                s.setPropellant(propellant);
                s.setDescription(desc);

                //SIMPLE VALIDATION
                if(name != null && name.length()>0)
                {
                    //THEN SAVE
                    if(helper.save(s))
                    {
                        //IF SAVED CLEAR EDITXT
                        nameEditTxt.setText("");
                        propTxt.setText("");
                        descTxt.setText("");

                        adapter=new MyAdapter(MainActivity.this,helper.retrieve());
                        rv.setAdapter(adapter);

                    }
                }else
                {
                    Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
                }

            }
        });

        d.show();
    }

}
(f). DetailActivity.java
  • Sí, la actividad de detalle aquí, para mostrar nuestros detalles.
  • Recibe los datos de la MainActivity vía Intent.
  • Muestra los datos en TextViews.

package com.tutorials.hp.firebaserecyclermdetail;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;

public class DetailActivity extends AppCompatActivity {

    TextView nameTxt,descTxt, propTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        nameTxt = (TextView) findViewById(R.id.nameDetailTxt);
        descTxt= (TextView) findViewById(R.id.descDetailTxt);
        propTxt = (TextView) findViewById(R.id.propellantDetailTxt);

        //GET INTENT
        Intent i=this.getIntent();

        //RECEIVE DATA
        String name=i.getExtras().getString("NAME_KEY");
        String desc=i.getExtras().getString("DESC_KEY");
        String propellant=i.getExtras().getString("PROP_KEY");

        //BIND DATA
        nameTxt.setText(name);
        descTxt.setText(desc);
        propTxt.setText(propellant);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

}

Diseños

(a). ActivityMain.xml
  • Contiene nuestro ContentMain.xml
  • Define nuestro ActionButton flotante.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_fitsSystemWindows="true"
    tools_context="com.tutorials.hp.firebaserecyclermdetail.MainActivity">

    <android.support.design.widget.AppBarLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android_id="@+id/toolbar"
            android_layout_width="match_parent"
            android_layout_height="?attr/actionBarSize"
            android_background="?attr/colorPrimary"
            app_popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android_id="@+id/fab"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_gravity="bottom|end"
        android_layout_margin="@dimen/fab_margin"
        android_src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(b). ContentMain.xml
  • Nuestra vista principal

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_paddingBottom="@dimen/activity_vertical_margin"
    android_paddingLeft="@dimen/activity_horizontal_margin"
    android_paddingRight="@dimen/activity_horizontal_margin"
    android_paddingTop="@dimen/activity_vertical_margin"
    app_layout_behavior="@string/appbar_scrolling_view_behavior"
    tools_context="com.tutorials.hp.firebaserecyclermdetail.MainActivity"
    tools_showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android_id="@+id/rv"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        />
</RelativeLayout>
(c). inputdialog.xml
  • define el diseño de nuestros diálogos de entrada

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android_orientation="vertical" android_layout_width="match_parent"
    android_layout_height="match_parent">

    <LinearLayout
        android_layout_width="fill_parent"
        android_layout_height="match_parent"
        android_layout_marginTop="?attr/actionBarSize"
        android_orientation="vertical"
        android_paddingLeft="15dp"
        android_paddingRight="15dp"
        android_paddingTop="50dp">

        <android.support.design.widget.TextInputLayout
            android_id="@+id/nameLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/nameEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Name" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android_id="@+id/propLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/propellantEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Propellant" />

        <android.support.design.widget.TextInputLayout
            android_id="@+id/descLayout"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <EditText
                android_id="@+id/descEditText"
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_singleLine="true"
                android_hint= "Description" />
        </android.support.design.widget.TextInputLayout>

        </android.support.design.widget.TextInputLayout>

        <Button android_id="@+id/saveBtn"
            android_layout_width="fill_parent"
            android_layout_height="wrap_content"
            android_text="Save"
            android_clickable="true"
            android_background="@color/colorAccent"
            android_layout_marginTop="40dp"
            android_textColor="@android:color/white"/>

    </LinearLayout>

</LinearLayout>
(d). Model.xml
  • define nuestros CardViews personalizados.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    android_orientation="horizontal" android_layout_width="match_parent"

    android_layout_margin="10dp"
    card_view_cardCornerRadius="5dp"
    card_view_cardElevation="5dp"
    android_layout_height="200dp">

        <LinearLayout
            android_orientation="vertical"
            android_layout_width="match_parent"
            android_layout_height="match_parent">

            <TextView
                android_layout_width="match_parent"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Name"
                android_id="@+id/nameTxt"
                android_padding="10dp"
                android_textColor="@color/colorAccent"
                android_textStyle="bold"
                android_layout_alignParentLeft="true"
                />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Description....................."
                android_lines="3"
                android_id="@+id/descTxt"
                android_padding="10dp"
                android_layout_alignParentLeft="true"
                />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceMedium"
                android_text="Propellant"
                android_textStyle="italic"
                android_id="@+id/propellantTxt" />

    </LinearLayout>

</android.support.v7.widget.CardView>
(f). activity_detail.xml
  • Contiene nuestro ContentDetail.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_fitsSystemWindows="true"
    tools_context="com.tutorials.hp.firebaserecyclermdetail.DetailActivity">

    <android.support.design.widget.AppBarLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android_id="@+id/toolbar"
            android_layout_width="match_parent"
            android_layout_height="?attr/actionBarSize"
            android_background="?attr/colorPrimary"
            app_popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_detail" />

    <android.support.design.widget.FloatingActionButton
        android_id="@+id/fab"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_gravity="bottom|end"
        android_layout_margin="@dimen/fab_margin"
        android_src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(g). content\detail.xml
  • Nuestra vista de detalle.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_paddingBottom="@dimen/activity_vertical_margin"
    android_paddingLeft="@dimen/activity_horizontal_margin"
    android_paddingRight="@dimen/activity_horizontal_margin"
    android_paddingTop="@dimen/activity_vertical_margin"
    app_layout_behavior="@string/appbar_scrolling_view_behavior"
    tools_context="com.tutorials.hp.firebaserecyclermdetail.DetailActivity"
    tools_showIn="@layout/activity_detail">

    <android.support.v7.widget.CardView
        android_orientation="horizontal" android_layout_width="match_parent"

        android_layout_margin="5dp"
        card_view_cardCornerRadius="10dp"
        card_view_cardElevation="5dp"

        android_layout_height="match_parent">

        <LinearLayout
            android_orientation="vertical"
            android_layout_width="match_parent"
            android_layout_height="match_parent"
            android_weightSum="1">

            <LinearLayout
                android_orientation="horizontal"
                android_layout_width="match_parent"
                android_layout_height="wrap_content">

                <ImageView
                    android_id="@+id/articleDetailImg"
                    android_layout_width="320dp"
                    android_layout_height="wrap_content"
                    android_paddingLeft="10dp"
                    android_layout_alignParentTop="true"
                    android_scaleType="centerCrop"
                    android_src="@drawable/spitzer" />

                <LinearLayout
                    android_orientation="vertical"
                    android_layout_width="match_parent"
                    android_layout_height="wrap_content">

                    <TextView
                        android_id="@+id/nameDetailTxt"
                        android_layout_width="wrap_content"
                        android_layout_height="wrap_content"
                        android_textAppearance="?android:attr/textAppearanceLarge"
                        android_padding="5dp"
                        android_minLines="1"
                        android_textStyle="bold"
                        android_textColor="@color/colorAccent"
                        android_text="Title" />

                </LinearLayout>
            </LinearLayout>

            <LinearLayout
                android_layout_width="fill_parent"
                android_layout_height="match_parent"
                android_layout_marginTop="?attr/actionBarSize"
                android_orientation="vertical"
                android_paddingLeft="5dp"
                android_paddingRight="5dp"
                android_paddingTop="5dp">

                <TextView
                    android_id="@+id/propellantDetailTxt"
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_textAppearance="?android:attr/textAppearanceLarge"
                    android_padding="5dp"
                    android_minLines="1"
                    android_text="DATE" />
                <TextView
                    android_id="@+id/descDetailTxt"
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_textAppearance="?android:attr/textAppearanceLarge"
                    android_padding="5dp"
                    android_textColor="#0f0f0f"
                    android_minLines="4"
                    android_text="Space craft details...." />

                <TextView
                    android_id="@+id/linkDetailTxt"
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_textAppearance="?android:attr/textAppearanceMedium"
                    android_padding="5dp"
                    android_textColor="@color/colorPrimaryDark"
                    android_textStyle="italic"
                    android_text="Link" />

            </LinearLayout>
        </LinearLayout>
    </android.support.v7.widget.CardView>

</RelativeLayout>

4. Descargar

Examinar
Descargar

Cómo correr

  1. Descargue el proyecto.
  2. Obtendrás un archivo comprimido, extráelo.
  3. Abre el Android Studio.
  4. Ahora cierra, el proyecto ya abierto.
  5. Desde la barra de menú haz clic en Archivo >Nuevo> Importar proyecto.
  6. Ahora elija una Carpeta de Destino, desde donde quiere importar el proyecto.
  7. Elija un Proyecto Android.
  8. Ahora haga clic en "Aceptar".
  9. Listo, ya has terminado de importar el proyecto, ahora edítalo.
  10. Tendrás que dirigirte a la consola de Firebase, crear la aplicación, luego descargar el archivo de configuración y añadirlo a tu proyecto en la carpeta de la aplicación.