En este tutorial veremos cómo crear y utilizar un recyclerview personalizado con checkboxes o radiobuttons y cómo manejar sus estados.

Conceptos que aprenderás

Este tutorial, a través de ejemplos, pretende que aprendas lo siguiente:

  1. Cómo crear recyclerview con checkboxes o radiobuttons y manejar adecuadamente sus estados.
  2. Cómo renderizar datos de la base de datos mysql, incluyendo datos booleanos, en un recyclerview con checkboxes.
  3. Cómo buscar/filtrar un recyclerview con checkboxes manteniendo sus estados de marcado/desmarcado.

Demostraciones

Estas son algunas de las demos que se crearán:

Demo de CheckBox


Kotlin RecyclerView CheckBox Example

Demo de RadioButton


Android RecyclerView RadioButton Example

Ejemplo 1: Android RecyclerView CheckBoxes - Mantener los Estados Comprobados

Este es un tutorial de checkboxes android recyclerview. Queremos ver como primero renderizar checkboxes, imágenes y texto en un recyclerview personalizado con cardviews. A continuación, obtener los cardviews seleccionados o marcados y mostrar n un mensaje Toast. Trabajamos con múltiples casillas de verificación para poder hacer una selección múltiple o simple de elementos en nuestro RecyclerView.

Esto nos enseñará cómo retener adecuadamente los estados de checkboxes en nuestro recyclerview a pesar del reciclaje de nuestros cardviews con checkboxes.

Entonces el usuario puede hacer clic en un botón de acción flotante para obtener los elementos seleccionados y mostrarlos en un mensaje Toast.

Estamos construyendo una comunidad vibrante en YouTube

Aquí está este tutorial en formato de vídeo.

Paso 1: Dependencias

No necesitamos ninguna dependencia especial para este proyecto. Todo lo que usamos son las dependencias estándar de androidx como recyclerview y cardview.

Paso 2: Crear el diseño de la actividad principal

activity_main.xml

Este será el diseño de nuestra actividad principal y lo escribiremos en XML. XML es un lenguaje de marcado que no sólo se utiliza para crear interfaces de usuario, sino también para intercambiar datos.

Este diseño será inflado en nuestra actividad principal. En la raíz tendremos un RelativeLayout.

Tenemos un TextView que es nuestro headerTextView para mostrar el encabezado de nuestra aplicación android.

Luego tenemos un RecyclerView que en este caso es nuestro adapterview. Este RecyclerView renderizará las imágenes, el texto y las casillas de verificación.

Debajo del RecyclerView tendremos un FloatingActionButton. Cuando los usuarios hagan clic en este botón FAB, mostraremos los elementos que han sido seleccionados en el recyclerview. Recuerda que nuestro recyclerview estará compuesto por cardviews que tienen imágenes, texto y checkboxes.

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

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    tools_context="info.camposha.checkablerecyclerviews.MainActivity">

    <TextView
        android_id="@+id/headerTextView"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_text="Spiritual Teachers"
        android_textAlignment="center"
        android_textAppearance="@style/TextAppearance.AppCompat.Large"
        android_textColor="@color/colorAccent" />

    <androidx.recyclerview.widget.RecyclerView
        android_id="@+id/myRecycler"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_layout_alignParentLeft="true"
        android_layout_alignParentStart="true"
        android_layout_below="@+id/headerTextView"
        android_layout_marginTop="30dp" />

    <android.support.design.widget.FloatingActionButton
        android_id="@+id/fab"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_alignParentBottom="true"
        android_layout_alignParentEnd="true"
        android_layout_alignParentRight="true"
        android_layout_gravity="bottom|end"
        android_src="@android:drawable/ic_dialog_email" />

</RelativeLayout>

Paso 3: Crear un elemento RecyclerView

model.xml

Este layout modelará un único cardview que se renderizará entre otras tarjetas de nuestro recyclerview.

Este layout modelará todas estas cardviews. En la raíz tenemos la CardView como nuestro elemento. CardView reside en el espacio de nombres android.support.v7.widget.

He establecido la elevación de la tarjeta a 5dp y el radio de la tarjeta a 10dp.

Dentro de ella tengo un RelativeLayout para organizar mis widgets de forma relativa.

Primero tenemos el ImageView para renderizar nuestra imagen. Luego TextViews para renderizar nuestros textos.

A la derecha de nuestro CardView tendremos un CheckBox que contendrá la propiedad de selección de cada cardview. Los CheckBox pueden estar marcados o desmarcados.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.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">

    <RelativeLayout
        android_layout_width="match_parent"
        android_layout_height="match_parent">
        <ImageView
            android_layout_width="150dp"
            android_layout_height="150dp"
            android_id="@+id/teacherImageView"
            android_padding="5dp"
            android_src="@drawable/cle" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceLarge"
            android_text="Teacher Name"
            android_id="@+id/nameTextView"
            android_padding="5dp"
            android_textColor="@color/colorAccent"
            android_layout_alignParentTop="true"
            android_layout_toRightOf="@+id/teacherImageView" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceMedium"
            android_text="Teacher Description..."
            android_id="@+id/descritionTextView"
            android_padding="5dp"
            android_layout_alignBottom="@+id/teacherImageView"
            android_layout_toRightOf="@+id/teacherImageView" />

        <CheckBox
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_id="@+id/myCheckBox"
            android_layout_alignParentRight="true"
            />

    </RelativeLayout>
</androidx.cardview.widget.CardView>

Paso 4: MainActivity.java

Especificar el paquete y añadir importaciones

Nuestra clase java residirá en un paquete, así que especificamos uno y añadimos las importaciones apropiadas.

Estas incluyen nuestro RecyclerView del paquete android.support.v7.widget y CheckBox del paquete android.widget.

package info.camposha.checkablerecyclerviews;

import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
Crear actividad

Una actividad es un componente de android que representa una interfaz de usuario.

Para convertir nuestra clase ordinaria en una actividad, la haremos derivar de AppCompatActivity:

public class MainActivity extends AppCompatActivity {..}
Crear nuestro POJO

A continuación crearemos una clase POJO, Plain OLd Java Object. Esto representará un único objeto Profesor.

Cada objeto POJO tendrá varias propiedades. Cada objeto será representado en su propia CardView en nuestro RecyclerView.

    public class SpiritualTeacher {
        //our properties.
    }

Una de esas propiedades será la propiedad isSelected, un valor booleano que nos indicará el estado de verificación de nuestra CardView.

Crear nuestro View Holder

Crearemos nuestra clase ViewHolder de RecyclerView derivando de la clase RecyclerView.ViewHolder.

También la clase implementará la interfaz View.OnClickListener. Esto nos permitirá capturar los eventos de clic de cada CardView.

    static class MyHolder extends RecyclerView.ViewHolder implements View.OnClickListener{...}
Crear el adaptador RecyclerView

A continuación venimos a crear nuestra clase RecyclerView.Adapter, la clase que será nuestra clase adaptadora.

    static class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {..}

Como clase adaptadora esta clase tiene dos funciones principales:

  1. Inflar nuestro Custom Model Layout en un View Object.
  2. Vincular el conjunto de datos a nuestras vistas infladas.

Los datos a vincular vendrán de un array personalizado, en este caso un array de SpiritualTeachers:

        public MyAdapter(Context c, SpiritualTeacher[] teachers) {
            this.c = c;
            this.teachers = teachers;
        }

Esta clase también mantendrá un arraylist que contendrá nuestros elementos comprobados.

        ArrayList<SpiritualTeacher> checkedTeachers=new ArrayList<>();

Los usuarios comprobarán los elementos de recyclerview y mantendremos esos elementos comprobados en este arraylist. Más tarde podemos mostrar estos elementos comprobados en un mensaje Toast.

Inflar el diseño en la vista

Esto tendrá lugar en nuestro adaptador RecyclerView, como habíamos acordado. Para ello necesitamos una clase LayoutInflater.

        @Override
        public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,null);
            MyHolder holder=new MyHolder(v);
            return holder;
        }

Entonces, como puedes ver, hemos pasado el objeto de vista inflado a nuestro constructor ViewHolder de RecyclerView.
Luego devolvemos la instancia View Holder.

Vinculación de datos

Vinculamos los datos dentro del método onBindViewHolder:

        @Override
        public void onBindViewHolder(MyHolder holder, int position) {
            final SpiritualTeacher teacher=teachers[position];
            holder.nameTxt.setText(teacher.getName());
            holder.posTxt.setText(teacher.getQuote());
            holder.myCheckBox.setChecked(teacher.isSelected());
            holder.img.setImageResource(teacher.getImage());
            ...
        }

Primero recibimos la posición del ítem en nuestro recyclerview y lo usamos para obtener el maestro actual de nuestro array.

A continuación, establecemos los widgets TextView, imageView y CheckBox con los valores de ese objeto.

Mantener los elementos marcados y no marcados

Luego escuchamos los eventos de clic de nuestra CardView. Obviamente, al hacer clic en el CheckBox cambiará el estado de ese checkbox.

Comprobamos estos cambios. Si se hace clic en la casilla de verificación, añadiremos el elemento en nuestra lista.

Si se desmarca eliminamos el elemento del arraylist.

            holder.setItemClickListener(new MyHolder.ItemClickListener() {
                @Override
                public void onItemClick(View v, int pos) {
                    CheckBox myCheckBox= (CheckBox) v;
                    SpiritualTeacher currentTeacher=teachers[pos];

                    if(myCheckBox.isChecked()) {
                        currentTeacher.setSelected(true);
                        checkedTeachers.add(currentTeacher);
                    }
                    else if(!myCheckBox.isChecked()) {
                        currentTeacher.setSelected(false);
                        checkedTeachers.remove(currentTeacher);
                    }
                }
            });

Veamos el código fuente completo.

Código completo

Aquí está el código completo de MainActivity.

package info.camposha.checkablerecyclerviews;

import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    public class SpiritualTeacher {
        private String name,quote;
        private int image;
        private boolean isSelected;

        public SpiritualTeacher(String name, String quote, int image) {
            this.name = name;
            this.quote = quote;
            this.image = image;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getQuote() {
            return quote;
        }
        public int getImage() {
            return image;
        }

        public boolean isSelected() {
            return isSelected;
        }

        public void setSelected(boolean selected) {
            isSelected = selected;
        }
    }
    static class MyHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

            ImageView img;
            TextView nameTxt,posTxt;
            CheckBox myCheckBox;

            ItemClickListener itemClickListener;

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

                nameTxt= itemView.findViewById(R.id.nameTextView);
                posTxt= itemView.findViewById(R.id.descritionTextView);
                img= itemView.findViewById(R.id.teacherImageView);
                myCheckBox= itemView.findViewById(R.id.myCheckBox);

                myCheckBox.setOnClickListener(this);
            }
            public void setItemClickListener(ItemClickListener ic)
            {
                this.itemClickListener=ic;
            }
            @Override
            public void onClick(View v) {
                this.itemClickListener.onItemClick(v,getLayoutPosition());
            }
            interface ItemClickListener {

                void onItemClick(View v,int pos);
            }
        }
    static class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {

        Context c;
        SpiritualTeacher[] teachers;
        ArrayList<SpiritualTeacher> checkedTeachers=new ArrayList<>();

        public MyAdapter(Context c, SpiritualTeacher[] teachers) {
            this.c = c;
            this.teachers = teachers;
        }

        //VIEWHOLDER IS INITIALIZED
        @Override
        public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,null);
            MyHolder holder=new MyHolder(v);
            return holder;
        }

        //DATA IS BOUND TO VIEWS
        @Override
        public void onBindViewHolder(MyHolder holder, int position) {
            final SpiritualTeacher teacher=teachers[position];
            holder.nameTxt.setText(teacher.getName());
            holder.posTxt.setText(teacher.getQuote());
            holder.myCheckBox.setChecked(teacher.isSelected());
            holder.img.setImageResource(teacher.getImage());

            holder.setItemClickListener(new MyHolder.ItemClickListener() {
                @Override
                public void onItemClick(View v, int pos) {
                    CheckBox myCheckBox= (CheckBox) v;
                    SpiritualTeacher currentTeacher=teachers[pos];

                    if(myCheckBox.isChecked()) {
                        currentTeacher.setSelected(true);
                        checkedTeachers.add(currentTeacher);
                    }
                    else if(!myCheckBox.isChecked()) {
                        currentTeacher.setSelected(false);
                        checkedTeachers.remove(currentTeacher);
                    }
                }
            });
        }

        @Override
        public int getItemCount() {
            return teachers.length;
        }

    }
    private SpiritualTeacher[] getTeachers() {
        SpiritualTeacher[] spiritualTeachers={
                new SpiritualTeacher("Rumi","Out beyond ideas of wrongdoing and rightdoing there is a field.I'll meet you there.",R.drawable.rumi),
                new SpiritualTeacher("Anthony De Mello","Don't Carry Over Experiences from the past",R.drawable.anthony_de_mello),
                new SpiritualTeacher("Eckhart Tolle","Walk as if you are kissing the Earth with your feet.",R.drawable.eckhart_tolle),
                new SpiritualTeacher("Meister Eckhart","Man suffers only because he takes seriously what the gods made for fun.",R.drawable.meister_eckhart),
                new SpiritualTeacher("Mooji","I have lived with several Zen masters -- all of them cats.",R.drawable.mooji),
                new SpiritualTeacher("Confucius","I'm simply saying that there is a way to be sane. I'm saying that you ",R.drawable.confucius),
                new SpiritualTeacher("Francis Lucille","The way out is through the door. Why is it that no one will use this method?",R.drawable.francis_lucille),
                new SpiritualTeacher("Thich Nhat Hanh","t is the power of the mind to be unconquerable.",R.drawable.thich),
                new SpiritualTeacher("Dalai Lama","It's like you took a bottle of ink and you threw it at a wall. Smash! ",R.drawable.dalai_lama),
                new SpiritualTeacher("Jiddu Krishnamurti","A student, filled with emotion and crying, implored, 'Why is there so much suffering?",R.drawable.jiddu_krishnamurti),
                new SpiritualTeacher("Osho","Only the hand that erases can write the true thing.",R.drawable.osho),
                new SpiritualTeacher("Sedata","Many have died; you also will die. The drum of death is being beaten.",R.drawable.sedata),
                new SpiritualTeacher("Allan Watts","Where there are humans, You'll find flies,And Buddhas.",R.drawable.allant_watts),
                new SpiritualTeacher("Leo Gura","Silence is the language of Om. We need silence to be able to reach our Self.",R.drawable.sadhguru),
                new SpiritualTeacher("Rupert Spira","One day in my shoes and a day for me in your shoes, the beauty of travel lies ",R.drawable.rupert_spira),
                new SpiritualTeacher("Sadhguru","Like vanishing dew,a passing apparition or the sudden flashnof lightning",R.drawable.sadhguru)
        };

        return spiritualTeachers;
    }
    StringBuilder sb=null;
    MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        adapter=new MyAdapter(this,getTeachers());

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

                int i=0;
                do {
                    SpiritualTeacher spiritualTeacher=adapter.checkedTeachers.get(i);
                    sb.append(spiritualTeacher.getName());
                    if(i != adapter.checkedTeachers.size()-1){
                        sb.append("n");
                    }
                    i++;

                }while (i < adapter.checkedTeachers.size());

                if(adapter.checkedTeachers.size()>0)
                {
                    Toast.makeText(MainActivity.this,sb.toString(),Toast.LENGTH_SHORT).show();
                }else
                {
                    Toast.makeText(MainActivity.this,"Please Check An Item First", Toast.LENGTH_SHORT).show();
                }
            }
        });

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

        //SET ADAPTER
        rv.setAdapter(adapter);

    }

}

Ejemplo 2: SingleChoice RecyclerView - con RadioButtons

Tutorial de SingleChoice RecyclerView para Android

En este tutorial queremos ver cómo crear un recyclerview de una sola opción. Esto es un recyclerview con
radiobuttons. El usuario puede seleccionar un solo ítem y nosotros abrimos la actividad de detalle del ítem mostrando así sus datos.

¿Por qué SingleChoice RecyclerView?

Bueno, la alternativa es el recyclerview de múltiples opciones, es decir, el recyclerview con casillas de verificación. Sin embargo, en algunos casos
sólo quiere que el usuario pueda seleccionar un solo elemento del recyclerview. Aquí es donde entran en juego los radiobuttons.

Sin embargo, en nuestro caso abriremos una actividad detallada cuando el usuario seleccione un radiobutton determinado. A continuación, utilizamos intents para
pasar datos a la actividad detallada.

¿Qué mostramos?

Bueno, mostramos imágenes, texto y radiobuttons. Normalmente las imágenes se renderizan en imageview. El texto
se renderizará en textview. Por otro lado los radiobuttons nos
nos muestran un estado compuesto, básicamente marcado o no.

Paso 1: Scripts Gradle

(a) Build.gradle

No se requiere ninguna dependencia especial. Añadimos CardView y recyclerview como nuestras dependencias.

La CardView contendrá nuestros objetos Galaxy. El RecyclerView contendrá múltiples cardviews. AppCompat nos dará la
AppCompatActivity de la que extiende nuestra MainActivity.

Paso 2: Crear Layouts

Tenemos tres layouts

1. activity_main.xml

Este layout se inflará en la MainActivity. Simplemente contiene nuestro RecyclerView. Yo le he dado al mío un color de fondo
color de fondo.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android_layout_width="match_parent"
    android_background="#009968"
    android_layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android_id="@+id/mRecylcerview"
        android_layout_width="match_parent"
        android_layout_height="match_parent" />
</RelativeLayout>

2. activity_detail.xml

El Layout para nuestra actividad Detail. Contiene imageview y textviews.to mostrar
nuestros datos.

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

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_background="#009688"
    tools_context=".DetailsActivity"
    tools_showIn="@layout/activity_detail">

    <androidx.cardview.widget.CardView
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_layout_margin="3dp"
        card_view_cardCornerRadius="3dp"
        card_view_cardElevation="5dp">

        <ScrollView
            android_layout_width="match_parent"
            android_layout_height="match_parent">

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

                <ImageView
                    android_id="@+id/galaxyImg"
                    android_layout_width="match_parent"
                    android_layout_height="200dp"
                    android_layout_alignParentTop="true"
                    android_padding="5dp"
                    android_scaleType="fitXY"
                    android_src="@drawable/placeholder" />

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

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

                        <TextView
                            android_id="@+id/nameLabel"
                            android_layout_width="0dp"
                            android_layout_weight="1"
                            android_layout_height="wrap_content"
                            android_maxLines="1"
                            android_padding="5dp"
                            android_text="NAME"
                            android_textColor="@color/colorAccent"
                            android_textAppearance="?android:attr/textAppearanceSmall"
                            android_textStyle="bold" />

                        <TextView
                            android_id="@+id/nameTxt"
                            android_layout_width="0dp"
                            android_layout_weight="2"
                            android_layout_height="wrap_content"
                            android_maxLines="1"
                            android_padding="5dp"
                            android_text="Milky Way"
                            android_textAppearance="?android:attr/textAppearanceSmall"/>
                    </LinearLayout>

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

                        <TextView
                            android_id="@+id/dateLabel"
                            android_layout_width="0dp"
                            android_layout_weight="1"
                            android_layout_height="wrap_content"
                            android_maxLines="1"
                            android_textColor="@color/colorAccent"
                            android_padding="5dp"
                            android_text="DATE"
                            android_textAppearance="?android:attr/textAppearanceSmall"
                            android_textStyle="bold" />

                        <TextView
                            android_id="@+id/dateDetailTextView"
                            android_layout_width="0dp"
                            android_layout_weight="2"
                            android_layout_height="wrap_content"
                            android_maxLines="1"
                            android_padding="5dp"
                            android_text="Today"
                            android_textAppearance="?android:attr/textAppearanceSmall"/>
                    </LinearLayout>

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

                        <TextView
                            android_id="@+id/descLabel"
                            android_layout_width="0dp"
                            android_layout_weight="1"
                            android_layout_height="wrap_content"
                            android_maxLines="1"
                            android_textColor="@color/colorAccent"
                            android_padding="5dp"
                            android_text="DESCRIPTION : "
                            android_textAppearance="?android:attr/textAppearanceSmall"
                            android_textStyle="bold" />

                        <TextView
                            android_id="@+id/descTxt"
                            android_layout_width="0dp"
                            android_layout_weight="2"
                            android_layout_height="wrap_content"
                            android_maxLines="10"
                            android_padding="5dp"
                            android_text="Description..."
                            android_textAppearance="?android:attr/textAppearanceSmall"/>
                    </LinearLayout>

                </LinearLayout>
            </LinearLayout>
        </ScrollView>
    </androidx.cardview.widget.CardView>
</RelativeLayout>

3. model.xml

Este es nuestro diseño de vista de artículos. Se inflará en nuestros elementos de vista recyclerview. Esto lo hará nuestro adaptador RecyclerView
adaptador.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    android_orientation="horizontal" android_layout_width="match_parent"

    android_layout_margin="1dp"
    card_view_cardCornerRadius="1dp"
    card_view_cardElevation="5dp"
    android_layout_height="135dp">

        <RelativeLayout
            android_layout_width="wrap_content"
            android_layout_height="match_parent">

        <ImageView
            android_layout_width="120dp"
            android_layout_height="120dp"
            android_id="@+id/mGalaxyImageView"
            android_padding="5dp"
            android_scaleType="fitXY"
            android_src="@drawable/placeholder" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceSmall"
            android_text="Name"
            android_id="@+id/mNameTxt"
            android_padding="5dp"
            android_textColor="@color/colorAccent"
            android_layout_alignParentTop="true"
            android_layout_toRightOf="@+id/mGalaxyImageView" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceSmall"
            android_text="Description"
            android_textStyle="italic"
            android_maxLines="3"
            android_id="@+id/mDescTxt"
            android_padding="5dp"
            android_layout_alignBottom="@+id/mGalaxyImageView"
            android_layout_toRightOf="@+id/mGalaxyImageView" />

            <RadioButton
                android_id="@+id/mRadioButton"
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_layout_alignParentRight="true" />

        </RelativeLayout>
</androidx.cardview.widget.CardView>

Paso 4: Escribir el código Java.

Tenemos las siguientes clases java para este proyecto:

  1. Galaxy.java
  2. RecyclerAdapter.java
  3. DetailsActivity.java
  4. MainActivity.java
(a).Galaxy.java

Esto representará nuestro objeto de datos. Es nuestra clase modelo y representa una galaxia con propiedades como:

    1. Nombre.
  1. Descripción
  2. Imagen.

Este es el código completo.

package info.camposha.singlechoicerecyclerview_vela;

import java.io.Serializable;

/**
 * Please take note that our data object will implement Serializable.This
 * will allow us to pass this serialized object to DetailsActivity,
 */
public class Galaxy implements Serializable{
    private String name,description;
    private int image;

    public Galaxy(String name, String description,int image) {
        this.name = name;
        this.description = description;
        this.image=image;
    }

    public String getName() {return name;}
    public String getDescription() {return description;}
    public int getImage() {return image;}

}

Puedes ver que hemos implementado la interfaz Serializable. Esto nos permite serializar nuestro objeto de datos para
que pueda ser transportado a la actividad DetailsActivity como un todo a través de intent.

(b). RecyclerAdapter.java

Esta es nuestra clase adaptadora. Inflará nuestro diseño del modelo en un objeto de la vista que puede ser representado por el recyclerview.
También vinculará los datos a esos objetos de vista inflados.

package info.camposha.singlechoicerecyclerview_vela;

import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.TextView;

import java.util.List;

public class RecyclerAdapter extends RecyclerView.Adapter<
RecyclerAdapter.RecyclerViewHolder> {

    /**
     * Let's start by defining our instance fields
     */
    private int selectedStarPosition = -1;
    private List<Galaxy> galaxies;
    private Context c;
    private AdapterView.OnItemClickListener onItemClickListener;

    /**
     * Let's create our constructor
     * @param context
     * @param mGalaxies
     */
    public RecyclerAdapter(Context context, List<Galaxy> mGalaxies) {
        this.c = context;
        this.galaxies = mGalaxies;
    }

    /**
     * OnCreateViewHolder - here is where we inflate our model layout
     * @param viewGroup
     * @param i
     * @return
     */
    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        final View v = LayoutInflater.from(c).inflate(R.layout.model, viewGroup, false);
        return new RecyclerViewHolder(v, this);
    }

    /**
     * OnBindViewHolder - Here's where we bind our data
     * @param viewHolder
     * @param position
     */
    @Override
    public void onBindViewHolder(RecyclerViewHolder viewHolder, final int position) {
        Galaxy galaxy = galaxies.get(position);
        try {
            viewHolder.bindData(galaxy, position);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * Let's return the number of items to be bound to our adapter.
     * @return
     */
    @Override
    public int getItemCount() {
        return galaxies.size();
    }

    /**
     * Let's receive our onItemClickListener and assign it to our local one.
     * @param onItemClickListener
     */
    public void setOnItemClickListener(AdapterView.OnItemClickListener
     onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    /**
     * When user clicks our itemView, we still invoke the onItemClick
     * @param holder
     */
    public void onItemHolderClick(RecyclerViewHolder holder) {
        if (onItemClickListener != null)
            onItemClickListener.onItemClick(null, holder.itemView,
             holder.getAdapterPosition(), holder.getItemId());
    }

    /**
     * Let's come create our ViewHolder class.
     */
    class RecyclerViewHolder extends RecyclerView.ViewHolder implements
     View.OnClickListener {

        private RecyclerAdapter mAdapter;
        private RadioButton mRadioButton;
        private TextView mNameTxt,mDescTxt;
        private ImageView mGalaxyImg;

        /**
         * In our constructor, we reference our itemView widgets.
         * @param itemView
         * @param mAdapter
         */
        public RecyclerViewHolder(View itemView, final RecyclerAdapter mAdapter) {
            super(itemView);
            this.mAdapter = mAdapter;

            mNameTxt = itemView.findViewById(R.id.mNameTxt);
            mDescTxt = itemView.findViewById(R.id.mDescTxt);
            mRadioButton = itemView.findViewById(R.id.mRadioButton);
            mGalaxyImg=itemView.findViewById(R.id.mGalaxyImageView);
            itemView.setOnClickListener(this);
            mRadioButton.setOnClickListener(this);
        }

        /**
         * Let's create a method that allows us bind our data.
         * @param galaxy
         * @param position
         */
        public void bindData(Galaxy galaxy, int position) {
            mRadioButton.setChecked(position == selectedStarPosition);
            mNameTxt.setText(galaxy.getName());
            mDescTxt.setText(galaxy.getDescription());
            mGalaxyImg.setImageResource(galaxy.getImage());
        }

        /**
         * Let's override our OnClick method.
         * @param v
         */
        @Override
        public void onClick(View v) {
            selectedStarPosition = getAdapterPosition();
            notifyItemRangeChanged(0, galaxies.size());
            mAdapter.onItemHolderClick(RecyclerViewHolder.this);
        }
    }
}
//end
(c). DetailsActivity.java

Nuestra clase de actividad de detalle. Esta mostrará los detalles de la galaxia pulsada.

package info.camposha.singlechoicerecyclerview_vela;

import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.TextView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DetailsActivity extends AppCompatActivity {

  TextView nameTxt, descTxt, dateDetailTextView;
  ImageView galaxyImg;

  //We start by initializing our widgets.
  private void initializeWidgets() {
    nameTxt = findViewById(R.id.nameTxt);
    descTxt = findViewById(R.id.descTxt);
    dateDetailTextView = findViewById(R.id.dateDetailTextView);
    descTxt = findViewById(R.id.descTxt);
    galaxyImg = findViewById(R.id.galaxyImg);
  }

  //This method will get todays date and return it as a string
  private String getDateToday() {
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    Date date = new Date();
    String today = dateFormat.format(date);
    return today;
  }

  //I'll create a method to receive and show data.
  private void receiveAndShowData() {
    //RECEIVE DATA FROM ITEMS ACTIVITY VIA INTENT
    Intent i = this.getIntent();
    Galaxy g= (Galaxy) i.getSerializableExtra("GALAXY_KEY");

    //SET RECEIVED DATA TO TEXTVIEWS AND IMAGEVIEWS
    nameTxt.setText(g.getName());
    descTxt.setText(g.getDescription());
    dateDetailTextView.setText(getDateToday());
    galaxyImg.setImageResource(g.getImage());
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);

    initializeWidgets();
    receiveAndShowData();
  }
}
//end
(d). MainActivity.java

Nuestra clase de actividad principal. Aquí es donde hacemos referencia a nuestro recyclerview y definimos nuestra fuente de datos.

package info.camposha.singlechoicerecyclerview_vela;

import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

    RecyclerView mRecyclerView;
    private RecyclerAdapter mAdapter;
    /**
     * Let's start by defining our data source.
     * @return
     */
    private ArrayList<Galaxy> getData()
    {
        ArrayList<Galaxy> galaxies=new ArrayList<>();
        Galaxy g=new Galaxy("Whirlpool",
                "The Whirlpool Galaxy, also known as Messier 51a, M51a, and NGC 5194, is an interacting grand-design spiral Galaxy with a Seyfert 2 active galactic nucleus in the constellation Canes Venatici.",
                R.drawable.whirlpool);
        galaxies.add(g);

        g=new Galaxy("Ring Nebular",
                "The Ring Nebula is a planetary nebula in the northern constellation of Lyra. Such objects are formed when a shell of ionized gas is expelled into the surrounding interstellar medium by a red giant star.",
                R.drawable.ringnebular);
        galaxies.add(g);

        g=new Galaxy("IC 1011",
                "C 1011 is a compact elliptical galaxy with apparent magnitude of 14.7, and with a redshift of z=0.02564 or 0.025703, yielding a distance of 100 to 120 Megaparsecs. Its light has taken 349.5 million years to travel to Earth.",
                R.drawable.ic1011);
        galaxies.add(g);

        g=new Galaxy("Cartwheel",
                "The Cartwheel Galaxy is a lenticular galaxy and ring galaxy about 500 million light-years away in the constellation Sculptor. It is an estimated 150,000 light-years diameter, and a mass of about 2.9–4.8 × 10⁹ solar masses; it rotates at 217 km/s.",
                R.drawable.cartwheel);
        galaxies.add(g);

        g=new Galaxy("Triangulumn",
                "The Triangulum Galaxy is a spiral Galaxy approximately 3 million light-years from Earth in the constellation Triangulum",
                R.drawable.triangulum);
        galaxies.add(g);

        g=new Galaxy("Small Magellonic Cloud",
                "The Small Magellanic Cloud, or Nubecula Minor, is a dwarf galaxy near the Milky Way. It is classified as a dwarf irregular galaxy.",
                R.drawable.smallamgellonic);
        galaxies.add(g);

        g=new Galaxy("Centaurus A",
                " Centaurus A or NGC 5128 is a galaxy in the constellation of Centaurus. It was discovered in 1826 by Scottish astronomer James Dunlop from his home in Parramatta, in New South Wales, Australia.",
                R.drawable.centaurusa);
        galaxies.add(g);

        g=new Galaxy("Ursa Minor",
                "The Milky Way is the Galaxy that contains our Solar System." +
                        " The descriptive milky is derived from the appearance from Earth of the Galaxy – a band of light seen in the night sky formed from stars",
                R.drawable.ursaminor);
        galaxies.add(g);

        g=new Galaxy("Large Magellonic Cloud",
                " The Large Magellanic Cloud is a satellite galaxy of the Milky Way. At a distance of 50 kiloparsecs, the LMC is the third-closest galaxy to the Milky Way, after the Sagittarius Dwarf Spheroidal and the.",
                R.drawable.largemagellonic);
        galaxies.add(g);

        g=new Galaxy("Milky Way",
                "The Milky Way is the Galaxy that contains our Solar System." +
                        " The descriptive milky is derived from the appearance from Earth of the Galaxy – a band of light seen in the night sky formed from stars",
                R.drawable.milkyway);
        galaxies.add(g);

        g=new Galaxy("Andromeda",
                "The Andromeda Galaxy, also known as Messier 31, M31, or NGC 224, is a spiral Galaxy approximately 780 kiloparsecs from Earth. It is the nearest major Galaxy to the Milky Way and was often referred to as the Great Andromeda Nebula in older texts.",
                R.drawable.andromeda);
        galaxies.add(g);

        g=new Galaxy("Messier 81",
                "Messier 81 is a spiral Galaxy about 12 million light-years away in the constellation Ursa Major. Due to its proximity to Earth, large size and active galactic nucleus, Messier 81 has been studied extensively by professional astronomers.",
                R.drawable.messier81);
        galaxies.add(g);

        g=new Galaxy("Own Nebular",
                " The Owl Nebula is a planetary nebula located approximately 2,030 light years away in the constellation Ursa Major. It was discovered by French astronomer Pierre Méchain on February 16, 1781",
                R.drawable.ownnebular);
        galaxies.add(g);

        g=new Galaxy("Messier 87",
                "Messier 87 is a supergiant elliptical galaxy in the constellation Virgo. One of the most massive galaxies in the local universe, it is notable for its large population of globular clusters—M87 contains",
                R.drawable.messier87);
        galaxies.add(g);

        g=new Galaxy("Cosmos Redshift",
                "Cosmos Redshift 7 is a high-redshift Lyman-alpha emitter Galaxy, in the constellation Sextans, about 12.9 billion light travel distance years from Earth, reported to contain the first stars —formed ",
                R.drawable.cosmosredshift);
        galaxies.add(g);

        g=new Galaxy("StarBust",
                "A starburst Galaxy is a Galaxy undergoing an exceptionally high rate of star formation, as compared to the long-term average rate of star formation in the Galaxy or the star formation rate observed in most other galaxies. ",
                R.drawable.starbust);
        galaxies.add(g);

        g=new Galaxy("Sombrero",
                "Sombrero Galaxy is an unbarred spiral galaxy in the constellation Virgo located 31 million light-years from Earth. The galaxy has a diameter of approximately 50,000 light-years, 30% the size of the Milky Way.",
                R.drawable.sombrero);
        galaxies.add(g);

        g=new Galaxy("Pinwheel",
                "The Pinwheel Galaxy is a face-on spiral galaxy distanced 21 million light-years away from earth in the constellation Ursa Major. ",
                R.drawable.pinwheel);
        galaxies.add(g);

        g=new Galaxy("Canis Majos Overdensity",
                "The Canis Major Dwarf Galaxy or Canis Major Overdensity is a disputed dwarf irregular galaxy in the Local Group, located in the same part of the sky as the constellation Canis Major. ",
                R.drawable.canismajoroverdensity);
        galaxies.add(g);

        g=new Galaxy("Virgo Stella Stream",
                " Group, located in the same part of the sky as the constellation Canis Major. ",
                R.drawable.virgostellarstream);
        galaxies.add(g);

        return galaxies;
    }

    /**
     * Let's create a method to open our detail activity and pass our object.
     * @param galaxy
     */
    private void openDetailActivity(Galaxy galaxy)
    {
        Intent i=new Intent(this,DetailsActivity.class);
        i.putExtra("GALAXY_KEY",galaxy);
        startActivity(i);
    }

    /**
     * Let's implemenent our onItemClick method
     * @param parent
     * @param view
     * @param position
     * @param id
     */
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Galaxy g=getData().get(position);
        Toast.makeText(MainActivity.this,String.valueOf(position)+". "+ g.getName()+" Chosen.", Toast.LENGTH_SHORT).show();
        openDetailActivity(g);
    }

    /**
     * Let's override our onCreate callback
     * @param savedInstanceState
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerView=findViewById(R.id.mRecylcerview);

        mAdapter = new RecyclerAdapter(this, getData());
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.setOnItemClickListener(this);
    }
}
Descargar

Puedes descargar el código fuente completo a continuación o ver el vídeo desde el enlace proporcionado.

No. Location Link
1. GitHub Direct Download
2. GitHub Browse
3. YouTube Video Tutorial
4. YouTube ProgrammingWizards TV Channel

Ejemplo 3: Kotlin Android RecyclerView - CardView con CheckBox,Images,Text y ItemClick

Kotlin Android RecyclerView con CheckBox, Imágenes, texto y ItemClick soporta Tutorial y Ejemplo.

Quiero mostrarte cómo puedes trabajar con el recyclerview en este tutorial y hacer cosas comunes como usarlo con checkboxes, imágenes, textview y también soportar eventos de click. Todo esto lo hacemos en un solo archivo MainActivity.kt.

Video Tutorial

Si prefieres un video tutorial entonces mira aquí:

Lo que se aprende

Estos son los conceptos que aprenderás:

  1. Cómo utilizar Recyclerview en android con el lenguaje de programación Kotlin.
  2. Cómo utilizar CheckBox con recyclerview y manejar los estados de la casilla de verificación adecuadamente.
  3. Cómo crear un recyclerview con imágenes y texto.
  4. Cómo soportar el evento de clic de un ítem en el recyclerview.

Herramientas utilizadas

Estas son las herramientas que he utilizado para este proyecto:

  1. Lenguaje de programación : Kotlin
  2. Framework - Android
  3. IDE - Android Studio.
  4. Emulador - Nox Player
  5. SO : Windows 8.1

Vamos a empezar.

Demo

Aquí está la demo de este proyecto:


Kotlin RecyclerView CheckBox

(a). Build.gradle

Nuestro nivel de aplicación build.gradle.
Aquí es donde añadimos nuestras dependencias. Especialmente nos interesan tres principales de ellas:

  1. AppCompat - Para darnos la AppCompatActivity de la que derivará nuestra MainActivity.
  2. Design Support - Para darnos el RecyclerView.
  3. CardView - Para darnos el Cardview.

(b). activity_main.xml

Este es el diseño de nuestra actividad principal. Aquí están los componentes que utilizamos:

    1. RelativeLayout - Para organizar nuestros otros widgets de forma relativa.
  1. TextView - Para mostrar el texto de la cabecera.
    1. RecyclerView - Para mostrar nuestros datos.
  2. Botón de acción flotante - Para mostrar los elementos marcados cuando se hace clic.

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

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    tools_context="com.devosha.kotlin_recyclerview_checkbox.MainActivity">

    <TextView
        android_id="@+id/headerTextView"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_text="Spiritual Teachers"
        android_textAlignment="center"
        android_textAppearance="@style/TextAppearance.AppCompat.Large"
        android_textColor="@color/colorAccent" />

    <androidx.recyclerview.widget.RecyclerView
        android_id="@+id/myRecycler"
        class="androidx.recyclerview.widget.RecyclerView"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_layout_alignParentLeft="true"
        android_layout_alignParentStart="true"
        android_layout_below="@+id/headerTextView"
        android_layout_marginTop="30dp" />

    <android.support.design.widget.FloatingActionButton
        android_id="@+id/fab"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_alignParentBottom="true"
        android_layout_alignParentEnd="true"
        android_layout_alignParentRight="true"
        android_layout_gravity="bottom|end"
        android_src="@android:drawable/ic_dialog_email" />

</RelativeLayout>

(c). model.xml

Este layout definirá nuestras vistas de elementos para nuestro recyclerview, las modelará. Básicamente será el renderizado de los datos de un único objeto SpiritualTeacher. En la raíz tenemos un CardView. Luego también tenemos:

  1. ImageView - Para renderizar la imagen del objeto SpiritualTeacher.
  2. TextVIew - Para renderizar su nombre así como la descripción.
  3. CheckBox - Para permitirnos seleccionar y deseleccionar las CardViews.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.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">

    <RelativeLayout
        android_layout_width="match_parent"
        android_layout_height="match_parent">
        <ImageView
            android_layout_width="150dp"
            android_layout_height="150dp"
            android_id="@+id/teacherImageView"
            android_padding="5dp"
            android_src="@drawable/cle" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceLarge"
            android_text="Teacher Name"
            android_id="@+id/nameTextView"
            android_padding="5dp"
            android_textColor="@color/colorAccent"
            android_layout_alignParentTop="true"
            android_layout_toRightOf="@+id/teacherImageView" />

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_textAppearance="?android:attr/textAppearanceMedium"
            android_text="Teacher Description..."
            android_id="@+id/descritionTextView"
            android_padding="5dp"
            android_layout_alignBottom="@+id/teacherImageView"
            android_layout_toRightOf="@+id/teacherImageView" />

        <CheckBox
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_id="@+id/myCheckBox"
            android_layout_alignParentRight="true"
            />

    </RelativeLayout>
</androidx.cardview.widget.CardView>

(d). MainActivity.kt

Esta es nuestra [actividad] principal (https://camposha.info/android/activity). Este es nuestro único archivo y aquí definiremos varias clases internas de kotlin. Esta clase derivará de la AppCompatActivity.

Crear objeto de datos

Comenzaremos definiendo una clase interna llamada Maestro Espiritual:

   inner class SpiritualTeacher(var name: String?, val quote: String, val image: Int) {
        var isSelected: Boolean = false
    }

Esta clase es nuestro objeto de datos. Recibirá sus parámetros a través del constructor. Además estamos manteniendo un simple booleano como se puede ver que mantendrá para nosotros el estado de selección de las CardViews. De hecho esta es la magia que nos permite seleccionar y deseleccionar nuestros elementos en nuestro recyclerview. Así, nuestro recyclerview no perderá el estado aunque nos desplacemos y los elementos del recyclerview se reciclen. Esto se debe a que los mantenemos como datos en nuestro objeto y no se ven afectados por el reciclaje.

Crear la clase Adapter RecyclerVew

Normalmente el Adapter tiene dos funciones principales. En primer lugar, inflar nuestros diseños personalizados y, en segundo lugar, vincular los datos a los widgets resultantes. Sin embargo recyclerview siempre va más allá al permitirnos reciclar elementos. Esto ahorra el consumo de memoria ya que inflar es un proceso costoso y tendría un impacto negativo en nuestra aplicación si lo hiciéramos para cada elemento del recyclerview.

Así que crearemos un adaptador:

    internal class MyAdapter(var c: Context, var teachers: Array<SpiritualTeacher>) : RecyclerView.Adapter<MyAdapter.MyHolder>() {..}

Lo hemos hecho derivar de la clase RecyclerView.Adapter.

Dentro del adaptador primero crearemos un arraylist que nos guarde los profesores que han sido comprobados:

        var checkedTeachers = ArrayList<SpiritualTeacher>()

Es dentro del método onCreateViewHolder() donde vamos a inflar nuestro model.xml en un objeto View. Para ello utilizamos la clase LayoutInflater.

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.model, null)
            return MyHolder(v)
        }

Aquí está el código fuente completo.

package com.devosha.kotlin_recyclerview_checkbox

import android.content.Context
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import androidx.appcompat.app.AppCompatActivity
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast

import java.util.ArrayList

/**
 * class: MainActivity
 * This class is deriving from androidx.appcompat.app.AppCompatActivity.
 */
class MainActivity : AppCompatActivity() {

    private val teachers: Array<SpiritualTeacher>
        get() =
            arrayOf(SpiritualTeacher("Rumi", "Out beyond ideas of wrongdoing and rightdoing there is a field.I'll meet you there.", R.drawable.rumi),
                    SpiritualTeacher("Anthony De Mello", "Don't Carry Over Experiences from the past", R.drawable.anthony_de_mello),
                    SpiritualTeacher("Eckhart Tolle", "Walk as if you are kissing the Earth with your feet.", R.drawable.eckhart_tolle),
                    SpiritualTeacher("Meister Eckhart", "Man suffers only because he takes seriously what the gods made for fun.", R.drawable.meister_eckhart),
                    SpiritualTeacher("Mooji", "I have lived with several Zen masters -- all of them cats.", R.drawable.mooji),
                    SpiritualTeacher("Confucius", "I'm simply saying that there is a way to be sane. I'm saying that you ", R.drawable.confucius),
                    SpiritualTeacher("Francis Lucille", "The way out is through the door. Why is it that no one will use this method?", R.drawable.francis_lucille),
                    SpiritualTeacher("Thich Nhat Hanh", "t is the power of the mind to be unconquerable.", R.drawable.thich),
                    SpiritualTeacher("Dalai Lama", "It's like you took a bottle of ink and you threw it at a wall. Smash! ", R.drawable.dalai_lama),
                    SpiritualTeacher("Jiddu Krishnamurti", "A student, filled with emotion and crying, implored, 'Why is there so much suffering?", R.drawable.jiddu_krishnamurti),
                    SpiritualTeacher("Osho", "Only the hand that erases can write the true thing.", R.drawable.osho),
                    SpiritualTeacher("Sedata", "Many have died; you also will die. The drum of death is being beaten.", R.drawable.sedata),
                    SpiritualTeacher("Allan Watts", "Where there are humans, You'll find flies,And Buddhas.", R.drawable.allant_watts),
                    SpiritualTeacher("Leo Gura", "Silence is the language of Om. We need silence to be able to reach our Self.", R.drawable.sadhguru),
                    SpiritualTeacher("Rupert Spira", "One day in my shoes and a day for me in your shoes, the beauty of travel lies ", R.drawable.rupert_spira),
                    SpiritualTeacher("Sadhguru", "Like vanishing dew,a passing apparition or the sudden flashnof lightning", R.drawable.sadhguru))
    internal var sb: StringBuilder? = null
    internal lateinit var adapter: MyAdapter

    inner class SpiritualTeacher(var name: String?, val quote: String, val image: Int) {
        var isSelected: Boolean = false
    }

    internal class MyAdapter(var c: Context, var teachers: Array<SpiritualTeacher>) : RecyclerView.Adapter<MyAdapter.MyHolder>() {
        var checkedTeachers = ArrayList<SpiritualTeacher>()

        //VIEWHOLDER IS INITIALIZED
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.model, null)
            return MyHolder(v)
        }

        //DATA IS BOUND TO VIEWS
        override fun onBindViewHolder(holder: MyHolder, position: Int) {
            val teacher = teachers[position]
            holder.nameTxt.text = teacher.name
            holder.posTxt.text = teacher.quote
            holder.myCheckBox.isChecked = teacher.isSelected
            holder.img.setImageResource(teacher.image)

            holder.setItemClickListener(object : MyHolder.ItemClickListener {
                override fun onItemClick(v: View, pos: Int) {
                    val myCheckBox = v as CheckBox
                    val currentTeacher = teachers[pos]

                    if (myCheckBox.isChecked) {
                        currentTeacher.isSelected = true
                        checkedTeachers.add(currentTeacher)
                    } else if (!myCheckBox.isChecked) {
                        currentTeacher.isSelected = false
                        checkedTeachers.remove(currentTeacher)
                    }
                }
            })
        }

        override fun getItemCount(): Int {
            return teachers.size
        }

        internal class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {

            var img: ImageView
            var nameTxt: TextView
            var posTxt: TextView
            var myCheckBox: CheckBox

            lateinit var myItemClickListener: ItemClickListener

            init {

                nameTxt = itemView.findViewById(R.id.nameTextView)
                posTxt = itemView.findViewById(R.id.descritionTextView)
                img = itemView.findViewById(R.id.teacherImageView)
                myCheckBox = itemView.findViewById(R.id.myCheckBox)

                myCheckBox.setOnClickListener(this)
            }

            fun setItemClickListener(ic: ItemClickListener) {
                this.myItemClickListener = ic
            }

            override fun onClick(v: View) {
                this.myItemClickListener.onItemClick(v, layoutPosition)
            }

            internal interface ItemClickListener {

                fun onItemClick(v: View, pos: Int)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        adapter = MyAdapter(this, teachers)

        val fab = findViewById(R.id.fab) as FloatingActionButton
        fab.setOnClickListener {
            sb = StringBuilder()

            var i = 0
            while (i < adapter.checkedTeachers.size) {
                val spiritualTeacher = adapter.checkedTeachers[i]
                sb!!.append(spiritualTeacher.name)
                if (i != adapter.checkedTeachers.size - 1) {
                    sb!!.append("n")
                }
                i++

            }

            if (adapter.checkedTeachers.size > 0) {
                Toast.makeText(this@MainActivity, sb!!.toString(), Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this@MainActivity, "Please Check An Item First", Toast.LENGTH_SHORT).show()
            }
        }

        //RECYCLER
        val rv = findViewById(R.id.myRecycler) as RecyclerView
        rv.layoutManager = LinearLayoutManager(this)
        rv.itemAnimator = DefaultItemAnimator()

        //SET ADAPTER
        rv.adapter = adapter

    }
// end
}

Ejemplo 4: Android MySQL - RecyclerView CheckBoxes - INSERT,SELECT,SHOW

Este es un tutorial de android mysql recyclerview con checkboxes. Vemos cómo trabajar tanto con valores de texto como booleanos con nuestra base de datos mysql.

  • Hoy exploramos cómo trabajar con valores booleanos y de texto con MySQL y RecyclerView.
  • Primero insertamos los datos en la base de datos MySQL.
  • Los componentes que usamos como vistas de entrada incluyen chcekbox, spinner y material edittext.
  • El usuario escribe el nombre de su nave espacial favorita en el texto de edición, luego selecciona el propulsor de esa nave espacial en un spinner.
  • Luego marca/desmarca una casilla para saber si esa tecnología existe o no.
  • Guardamos los datos en MySQL al hacer clic en el botón.
  • Al hacer clic en el botón "recuperar", seleccionamos los datos de MySQL y vinculamos este texto y booleano a nuestro Checked RecyclerView, RecyclerView con CheckBoxes.

En primer lugar, déjame decir que tenemos el código fuente completo y bien comentado para descargarlo como una referencia completa.Hemos incluido el archivo PHP que utilizamos.Lo colocarás en el directorio raíz de tu servidor y modificarás cosas como el nombre de usuario, el nombre de la tabla, etc.

Video Tutorial(ProgrammingWizards TV Channel)

Bueno, tenemos un video tutorial como alternativa a esto. Si usted prefiere tutoriales como este entonces sería bueno que suscribirse a nuestro canal de YouTube.

Básicamente tenemos una televisión de programación donde hacemos tutoriales diarios especialmente de android.

Android MySQL RecyclerView CheckBoxes Insert, Select Show Ejemplo

Veamos nuestro ejemplo:

Android MySQL RecyclerView

Tabla MySQL

Esta es la estructura de nuestra tabla mysql:

Estructura de la tabla

Estructura del proyecto

Aquí está la estructura de nuestro proyecto.

Estructura del proyecto

1. Código PHP

Aquí está nuestro código php:

(a) Constantes.php

Nuestra clase PHP para mantener las constantes de la base de datos como el nombre del servidor, el nombre de la base de datos, el nombre de usuario y la contraseña. Estas credenciales serán necesarias para que podamos conectarnos a la base de datos MySQL.

<?php

class Constants
{
    //DATABASE DETAILS
    static $DB_SERVER="localhost";
    static $DB_NAME="galileoDB";
    static $USERNAME="root";
    static $PASSWORD="";
    const TB_NAME="galileoTB";
    //STATEMENTS
    static $SQL_SELECT_ALL="SELECT * FROM galileoTB";
}
(b) CRUD.php

Este archivo PHP nos permitirá recibir datos del cliente HTTP escuchando y manejando peticiones. Manejamos esas peticiones iniciando las acciones CRUD definidas en nuestra clase DBAdapater.php.

<?php

require_once("/DBAdapter.php");
if($_POST['action']=="save"){

         $dbAdapter=new DBAdapter();
         $name=$_POST['name'];
         $propellant=$_POST['propellant'];
         $technologyexists=$_POST['technologyexists'];
        $dbAdapter->insert(array($name,$propellant,$technologyexists));
}
else if($_POST['action']=="update")
{
         $dbAdapter=new DBAdapter();
         $id=$_POST['id'];
         $name=$_POST['name'];
         $propellant=$_POST['propellant'];
         $technologyexists=$_POST['technologyexists'];
        $dbAdapter->update($id,array($name,$propellant,$technologyexists));

}
else if($_POST['action']=="delete")
{
         $dbAdapter=new DBAdapter();
         $id=$_POST['id'];

        $dbAdapter->delete($id);
}
?>
(c) DBAdapter.php

Este archivo PHP contendrá funciones que nos permitirán realizar operaciones CRUD en nuestra base de datos MySQL. Dichas acciones incluyen la inserción y recuperación de datos hacia y desde la base de datos.

<?php

require_once("/Constants.php");
class DBAdapter
{
/*******************************************************************************************************************************************/
/*
   1.CONNECT TO DATABASE.
   2. RETURN CONNECTION OBJECT
*/
    public function connect()
    {

       $con=mysqli_connect(Constants::$DB_SERVER,Constants::$USERNAME,Constants::$PASSWORD,Constants::$DB_NAME);
        if(mysqli_connect_error(!$con))
        {
           // echo "Unable To Connect";
            return null;
        }else
        {

            return $con;
        }
    }
    /*******************************************************************************************************************************************/
/*
   1.INSERT SPACECRAFT INTO DATABASE
 */
    public function insert($s)
    {
        // INSERT
        $con=$this->connect();

        if($con != null)
        {
            $sql="INSERT INTO galileoTB(name,propellant,technologyexists) VALUES('$s[0]','$s[1]','$s[2]')";
            try
            {
                $result=mysqli_query($con,$sql);
                if($result)
                {
                    print(json_encode(array("Success")));
                }else
                {
                    print(json_encode(array("Unsuccessfull")));
                }
            }catch (Exception $e)
            {
               print(json_encode(array("PHP EXCEPTION : CAN'T SAVE TO MYSQL. "+$e->getMessage())));
            }
        }else{
            print(json_encode(array("PHP EXCEPTION : CAN'T CONNECT TO MYSQL. NULL CONNECTION.")));
        }
        mysqli_close($con);
    }
/*******************************************************************************************************************************************/
/*
   1.SELECT FROM DATABASE.
*/
    public function select()
    {
       $con=$this->connect();
        if($con != null)
        {
            $retrieved=mysqli_query($con,Constants::$SQL_SELECT_ALL);
            if($retrieved)
            {
                while($row=mysqli_fetch_array($retrieved))
                {

                   // echo $row["name"] ,"    t | ",$row["propellant"],"</br>";
                   $spacecrafts[]=$row;
                }
                print(json_encode($spacecrafts));
            }else
            {
                 print(json_encode(array("PHP EXCEPTION : CAN'T RETRIEVE FROM MYSQL. ")));
            }
        }else{
            print(json_encode(array("PHP EXCEPTION : CAN'T CONNECT TO MYSQL. NULL CONNECTION.")));
        }
        mysqli_close($con);
    }
/*******************************************************************************************************************************************/
/*
   1.UPDATE  DATABASE.

*/
    public function update($id, $s)
    {
        // UPDATE
        $con=$this->connect();

        if($con != null)
        {
            $sql="UPDATE galileoTB SET name='$s[0]',propellant='$s[1]',technologyexists='$s[2]' WHERE id='$id'";
            try
            {
                $result=mysqli_query($con,$sql);
                if($result)
                {
                    print(json_encode(array("Successfully Updated")));
                }else
                {
                    print(json_encode(array("Not Successfully Updated")));
                }
            }catch (Exception $e)
            {
                 print(json_encode(array("PHP EXCEPTION : CAN'T UPDATE INTO MYSQL. "+$e->getMessage())));
            }
        }else{
            print(json_encode(array("PHP EXCEPTION : CAN'T CONNECT TO MYSQL. NULL CONNECTION.")));
        }
        mysqli_close($con);
    }
/*******************************************************************************************************************************************/
/*
   1.DELETE SPACECRAFT FROM DATABASE.

*/
    public function delete($id)
    {
        $con=$this->connect();

        if($con != null)
        {
//            $name=$_POST['Name'];
//            $pos=$_POST['Position'];
//            $team=$_POST['Team'];
            $sql="DELETE FROM galileoTB WHERE id='$id'";
            try
            {
                $result=mysqli_query($con,$sql);
                if($result)
                {
                    print(json_encode(array("Successfully Deleted")));
                }else
                {
                    print(json_encode(array("Not Successfully Deleted")));
                }
            }catch (Exception $e)
            {
                print(json_encode(array("PHP EXCEPTION : CAN'T DELETE FROM MYSQL. "+$e->getMessage())));
            }
        }else{
            print(json_encode(array("PHP EXCEPTION : CAN'T CONNECT TO MYSQL. NULL CONNECTION.")));
        }
        mysqli_close($con);
    }

}
(d) Index.php

<?php

require_once("/DBAdapter.php");
    $dbAdapter=new DBAdapter();
    $dbAdapter->select();
?>

2. Scripts de Gradle

Aquí están nuestros scripts gradle en nuestro(s) archivo(s) build.gradle.

(a). build.gradle(app)

Aquí está nuestro archivo build.gradle a nivel de aplicación. Tenemos el DSL de dependencias donde añadimos nuestras dependencias.

Este archivo se llama build.gradle de nivel de aplicación ya que se encuentra en la carpeta app del proyecto.

Si estás usando la versión 3 y superior de Android Studio usa la palabra clave implementation mientras que si estás usando una versión menor a la 3 entonces sigue usando la palabra clave compile.

Una vez que hayas modificado este archivo build.gradle tienes que sincronizar tu proyecto. Android Studio le pedirá que lo haga.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:appcompat-v7:24.2.0'
    implementation 'com.android.support:design:24.2.0'
    implementation 'com.android.support:cardview-v7:24.2.0'
    implementation 'com.amitshekhar.android:android-networking:0.2.0'
}

Estamos utilizando Fast Android Networking Library como nuestro cliente HTTP. Puedes utilizar versiones más nuevas.

3. Recursos

La plataforma Android proporciona una forma potente y flexible de añadir contenido estático como recurso.

Estos contenidos estáticos también serán empaquetados en el archivo APK. El contenido estático se almacenará como un recurso o como un activo.

Los recursos pertenecen a un tipo determinado. Estos tipos pueden ser:

  1. Dibujable.
  2. Trazado.
  3. Valor.

Empecemos por ver los recursos del layout

(a). model.xml

Nuestro layout del modelo de filas.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.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="Propellant....................."
                android_id="@+id/txtPropellant"
                android_padding="10dp"
                android_layout_alignParentLeft="true"
                />
            <CheckBox
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textSize="25dp"
                android_id="@+id/chkTechExists"
                android_checked="true" />

    </LinearLayout>

</androidx.cardview.widget.CardView>
(b). content_main.xml

<?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.mysqlrecyclerbool.MainActivity"
    tools_showIn="@layout/activity_main">
<!--INPUT VIEWS-->
    <LinearLayout
        android_orientation="vertical"
        android_layout_width="match_parent"
        android_layout_height="wrap_content">

        <android.support.design.widget.TextInputEditText
            android_id="@+id/nameTxt"
            android_hint="Name"
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_textStyle="bold"
            android_textSize="25dp"
            android_enabled="true"
            android_focusable="true" />

        <LinearLayout
            android_orientation="horizontal"
            android_padding="5dp"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">
            <TextView
                android_textSize="25dp"
                android_text="Propellant"
                android_textStyle="bold"
                android_layout_width="250dp"
                android_layout_height="wrap_content" />
            <Spinner
                android_id="@+id/sp"
                android_textSize="25dp"
                android_textStyle="bold"
                android_layout_width="wrap_content"
                android_layout_height="wrap_content" />
        </LinearLayout>

        <LinearLayout
            android_orientation="horizontal"
            android_padding="5dp"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">
            <TextView
                android_textSize="25dp"
                android_text="Technology Exists ??"
                android_textStyle="bold"
                android_layout_width="250dp"
                android_layout_height="wrap_content" />
            <CheckBox
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textSize="25dp"
                android_id="@+id/techExists"
                android_checked="true" />
        </LinearLayout>
<!--BUTTONS-->
        <RelativeLayout
            android_orientation="horizontal"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

            <Button android_id="@+id/addBtn"
                android_layout_width="wrap_content"
                android_layout_height="60dp"
                android_text="Save"
                android_clickable="true"
                android_padding="5dp"
                android_background="#009968"
                android_textColor="@android:color/white"
                android_textStyle="bold"
                android_textSize="20dp" />

            <Button android_id="@+id/refreshBtn"
                android_layout_width="wrap_content"
                android_layout_height="60dp"
                android_text="Retrieve"
                android_padding="5dp"
                android_clickable="true"
                android_background="#f38630"
                android_textColor="@android:color/white"
                android_layout_alignParentTop="true"
                android_layout_alignParentRight="true"
                android_layout_alignParentEnd="true"
                android_textStyle="bold"
                android_textSize="20dp" />

        </RelativeLayout>
<!--RECYCLERVIEW-->
        <androidx.recyclerview.widget.RecyclerView
            android_id="@+id/rv"
            android_layout_width="match_parent"
            android_layout_height="wrap_content">

        </androidx.recyclerview.widget.RecyclerView>

    </LinearLayout>
</RelativeLayout>
(c). activity_main.xml

Este diseño se inflará en la interfaz de usuario de la actividad principal. Esto ocurrirá a través del método setContentView() de la actividad que requerirá que le pasemos el layout.

Lo haremos dentro del método onCreate() de 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.mysqlrecyclerbool.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>

3. Código Java.

Las aplicaciones Android pueden ser escritas principalmente en Java o Kotlin. Sin embargo, hoy en día hay muchos frameworks como Flutter que también utilizan lenguajes como Dart.

En esta clase estamos utilizando el lenguaje de programación Java.

Tendremos estas clases en nuestro proyecto.

(a). Nave espacial.java

Primero vamos a definir las propiedades de nuestra nave espacial ficticia :

package com.tutorials.hp.mysqlrecyclerbool.mModel;

public class Spacecraft {

    /*
    INSTANCE FIELDS
     */
    private int id;
    private String name;
    private String propellant;
    private int technologyExists;

    /*
    GETTERS AND SETTERS
     */
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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 int getTechnologyExists() {
        return technologyExists;
    }

    public void setTechnologyExists(int technologyExists) {
        this.technologyExists = technologyExists;
    }

    /*
    TOSTRING
     */
    @Override
    public String toString() {
        return name;
    }
}

Estructura de la tabla MySQL

(b). MySQLClient.java

Estamos utilizando la biblioteca de red de Android para nuestras llamadas de red.Lo hace en el hilo de fondo y es fácil de usar y rápido.Nos devolverá respuestas JSOn que podemos analizar fácilmente.A continuación, nuestro cliente MySQL.

package com.tutorials.hp.mysqlrecyclerbool.mMySQL;

import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

import com.androidnetworking.AndroidNetworking;
import com.androidnetworking.common.Priority;
import com.androidnetworking.error.ANError;
import com.androidnetworking.interfaces.JSONArrayRequestListener;
import com.tutorials.hp.mysqlrecyclerbool.mAdapter.MyAdapter;
import com.tutorials.hp.mysqlrecyclerbool.mModel.Spacecraft;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MySQLClient {

    //SAVE/RETRIEVE URLS
    private static final String DATA_INSERT_URL="http://10.0.2.2/android/Aristotle/crud.php";
    private static final String DATA_RETRIEVE_URL="http://10.0.2.2/android/Aristotle/index.php";

    //INSTANCE FIELDS
    private final Context c;
    private MyAdapter adapter ;

    public MySQLClient(Context c) {
        this.c = c;

    }
    /*
   SAVE/INSERT
    */
    public void add(Spacecraft s, final View...inputViews)
    {
        if(s==null)
        {
            Toast.makeText(c, "No Data To Save", Toast.LENGTH_SHORT).show();
        }
        else
        {
            AndroidNetworking.post(DATA_INSERT_URL)

                    .addBodyParameter("action","save")
                    .addBodyParameter("name",s.getName())
                    .addBodyParameter("propellant",s.getPropellant())
                    .addBodyParameter("technologyexists",String.valueOf(s.getTechnologyExists()))
                    .setTag("TAG_ADD")
                    .build()
                    .getAsJSONArray(new JSONArrayRequestListener() {
                        @Override
                        public void onResponse(JSONArray response) {

                            if(response != null)
                                try {
                                    //SHOW RESPONSE FROM SERVER
                                    String responseString = response.get(0).toString();
                                    Toast.makeText(c, "PHP SERVER RESPONSE : " + responseString, Toast.LENGTH_SHORT).show();

                                    if (responseString.equalsIgnoreCase("Success")) {
                                        //RESET VIEWS
                                        EditText nameTxt = (EditText) inputViews[0];
                                        Spinner spPropellant = (Spinner) inputViews[1];

                                        nameTxt.setText("");
                                        spPropellant.setSelection(0);
                                    }else
                                    {
                                        Toast.makeText(c, "PHP WASN'T SUCCESSFUL. ", Toast.LENGTH_SHORT).show();

                                    }

                                } catch (JSONException e) {
                                    e.printStackTrace();
                                    Toast.makeText(c, "GOOD RESPONSE BUT JAVA CAN'T PARSE JSON IT RECEIVED : "+e.getMessage(), Toast.LENGTH_SHORT).show();
                                }

                        }

                        //ERROR
                        @Override
                        public void onError(ANError anError) {
                            Toast.makeText(c, "UNSUCCESSFUL :  ERROR IS : "+anError.getMessage(), Toast.LENGTH_SHORT).show();
                        }

                    });

        }
    }

    /*
    RETRIEVE/SELECT/REFRESH
     */
    public void retrieve(final RecyclerView rv)
    {
        final ArrayList<Spacecraft> spacecrafts = new ArrayList<>();

        AndroidNetworking.get(DATA_RETRIEVE_URL)
                .setPriority(Priority.HIGH)
                .build()
                .getAsJSONArray(new JSONArrayRequestListener() {
                    @Override
                    public void onResponse(JSONArray response) {
                        JSONObject jo;
                        Spacecraft s;
                        try
                        {
                            for(int i=0;i<response.length();i++)
                            {
                                jo=response.getJSONObject(i);

                                int id=jo.getInt("id");
                                String name=jo.getString("name");
                                String propellant=jo.getString("propellant");
                                String techExists=jo.getString("technologyexists");

                                s=new Spacecraft();
                                s.setId(id);
                                s.setName(name);
                                s.setPropellant(propellant);
                                s.setTechnologyExists(techExists.equalsIgnoreCase("1") ? 1 : 0);

                                spacecrafts.add(s);
                            }

                            //SET TO RECYCLERVIEW
                            adapter =new MyAdapter(c,spacecrafts);
                            rv.setAdapter(adapter);

                        }catch (JSONException e)
                        {
                            Toast.makeText(c, "GOOD RESPONSE BUT JAVA CAN'T PARSE JSON IT RECEIEVED. "+e.getMessage(), Toast.LENGTH_LONG).show();

                        }

                    }

                    //ERROR
                    @Override
                    public void onError(ANError anError) {
                        anError.printStackTrace();
                        Toast.makeText(c, "UNSUCCESSFUL :  ERROR IS : "+anError.getMessage(), Toast.LENGTH_LONG).show();

                    }

                });

    }

}
(c). MyViewHolder.java

Nuestra clase ViewHolder.

package com.tutorials.hp.mysqlrecyclerbool.mAdapter;

import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

import com.tutorials.hp.mysqlrecyclerbool.R;

public class MyViewHolder extends RecyclerView.ViewHolder {

    TextView txtName,txtPropellant;
    CheckBox chkTechExists;
    public MyViewHolder(View view) {
        super(view);

         txtName = (TextView) view.findViewById(R.id.nameTxt);
         txtPropellant = (TextView) view.findViewById(R.id.txtPropellant);

         chkTechExists = (CheckBox) view.findViewById(R.id.chkTechExists);
    }
}
(d). MyAdapter.java

A continuación se muestra nuestra clase RecyclerView.Adapter.Dado que MySQL no tiene un tipo de dato booleano nativo.Deberemos mapear nuestros valores booleanos de checkbox a enteros anulables.

package com.tutorials.hp.mysqlrecyclerbool.mAdapter;

import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tutorials.hp.mysqlrecyclerbool.R;
import com.tutorials.hp.mysqlrecyclerbool.mModel.Spacecraft;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    /*
    INSTANCE FIELDS
     */
    private Context c;
    private ArrayList<Spacecraft> spacecrafts;

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

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

    /*
    BIND DATA
     */
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {

        Spacecraft s=spacecrafts.get(position);

        holder.txtName.setText(s.getName());
        holder.txtPropellant.setText(s.getPropellant());
        holder.chkTechExists.setChecked(s.getTechnologyExists()==1);
    }

    /*
    TOTAL NUM OF SPACECRAFTS
     */
    @Override
    public int getItemCount() {
        return spacecrafts.size();
    }
}
(d). MainActivity.java

Esta es nuestra actividad de lanzamiento como el nombre sugiere. Esto significa que será el principal punto de entrada a nuestra aplicación en el sentido de que cuando el usuario haga clic en el icono de nuestra aplicación, esta actividad se renderizará primero.

Reemplazamos un método llamado onCreate(). Aquí comenzaremos por inflar nuestro diseño principal a través del método setContentView().

Nuestra actividad principal es en realidad una activity ya que deriva de la AppCompatActivity.

package com.tutorials.hp.mysqlrecyclerbool;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TextInputEditText;
import androidx.appcompat.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.Toast;

import com.tutorials.hp.mysqlrecyclerbool.mAdapter.MyAdapter;
import com.tutorials.hp.mysqlrecyclerbool.mModel.Spacecraft;
import com.tutorials.hp.mysqlrecyclerbool.mMySQL.MySQLClient;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    //INSTANCE FIELDS
    private TextInputEditText txtName;
    private CheckBox chkTechnologyExists;
    private Spinner spPropellant;
    private RecyclerView rv;
    private Button btnAdd,btnRetrieve;

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

        //REFERENCE VIEWS
        this.initializeViews();

        populatePropellants();

        //HANDLE EVENTS
        this.handleClickEvents();

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv.setAdapter(new MyAdapter(MainActivity.this,new ArrayList<Spacecraft>()));
            }
        });

    }

    /*
    REFERENCE VIEWS
     */
    private void initializeViews()
    {

        txtName= (TextInputEditText) findViewById(R.id.nameTxt);
        chkTechnologyExists= (CheckBox) findViewById(R.id.techExists);
        spPropellant= (Spinner) findViewById(R.id.sp);
        rv= (RecyclerView) findViewById(R.id.rv);

        btnAdd= (Button) findViewById(R.id.addBtn);
        btnRetrieve= (Button) findViewById(R.id.refreshBtn);

        rv.setLayoutManager(new LinearLayoutManager(MainActivity.this));

    }

    /*
    HANDLE CLICK EVENTS
     */
    private void handleClickEvents()
    {
        //EVENTS : ADD
        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //GET VALUES
                String name=txtName.getText().toString();
                String propellant=spPropellant.getSelectedItem().toString();
                Boolean technologyexists=chkTechnologyExists.isChecked();

                //BASIC CLIENT SIDE VALIDATION
                if((name.length()<1 || propellant.length()<1  ))
                {
                    Toast.makeText(MainActivity.this, "Please Enter all Fields", Toast.LENGTH_SHORT).show();
                }
                else
                {
                    //SAVE

                    Spacecraft s=new Spacecraft();
                    s.setName(name);
                    s.setPropellant(propellant);
                    s.setTechnologyExists(technologyexists ? 1 : 0);

                    new MySQLClient(MainActivity.this).add(s,txtName,spPropellant);
                }
            }
        });

        //EVENTS : RETRIEVE
        btnRetrieve.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new MySQLClient(MainActivity.this).retrieve(rv);

            }
        });

    }

    private void populatePropellants()
    {
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item);

        adapter.add("None");
        adapter.add("Chemical Energy");
        adapter.add("Nuclear Energy");
        adapter.add("Laser Beam");
        adapter.add("Anti-Matter");
        adapter.add("Plasma Ions");
        adapter.add("Warp Drive");

        spPropellant.setAdapter(adapter);
        spPropellant.setSelection(0);

    }
}

AndroidManifest.xml

Asegúrate de añadir el permiso para la conectividad a internet.

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

    <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>
    </application>

</manifest>

Descargar

Hey, todo está en el código fuente de referencia que está bien comentado y fácil de entender y se puede descargar a continuación.

También revisa nuestro video tutorial es más detallado y se explica en el paso a paso.

No. Location Link
1. GitHub Direct Download
2. GitHub Browse
3. YouTube Video Tutorial

Categorizado en:

Etiquetado en: