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:
- Cómo crear recyclerview con checkboxes o radiobuttons y manejar adecuadamente sus estados.
- Cómo renderizar datos de la base de datos mysql, incluyendo datos booleanos, en un recyclerview con checkboxes.
- 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
Demo de RadioButton
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:
- Inflar nuestro Custom Model Layout en un View Object.
- 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:
- Galaxy.java
- RecyclerAdapter.java
- DetailsActivity.java
- MainActivity.java
(a).Galaxy.java
Esto representará nuestro objeto de datos. Es nuestra clase modelo y representa una galaxia con propiedades como:
-
- Nombre.
- Descripción
- 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:
- Cómo utilizar Recyclerview en android con el lenguaje de programación Kotlin.
- Cómo utilizar CheckBox con recyclerview y manejar los estados de la casilla de verificación adecuadamente.
- Cómo crear un recyclerview con imágenes y texto.
- 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:
- Lenguaje de programación : Kotlin
- Framework - Android
- IDE - Android Studio.
- Emulador - Nox Player
- SO : Windows 8.1
Vamos a empezar.
Demo
Aquí está la demo de este proyecto:
(a). Build.gradle
Nuestro nivel de aplicación build.gradle
.
Aquí es donde añadimos nuestras dependencias. Especialmente nos interesan tres principales de ellas:
- AppCompat - Para darnos la AppCompatActivity de la que derivará nuestra
MainActivity
. - Design Support - Para darnos el RecyclerView.
- 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:
-
- RelativeLayout - Para organizar nuestros otros widgets de forma relativa.
- TextView - Para mostrar el texto de la cabecera.
-
- RecyclerView - Para mostrar nuestros datos.
- 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:
- ImageView - Para renderizar la imagen del objeto
SpiritualTeacher
. - TextVIew - Para renderizar su nombre así como la descripción.
- 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:
Tabla MySQL
Esta es la estructura de nuestra tabla mysql:
Estructura del proyecto
Aquí está la estructura de nuestro 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:
- Dibujable.
- Trazado.
- 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;
}
}
(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 |