Professional Documents
Culture Documents
En Aplicaciones Android
En este artículo aprenderás a crear una app con una base de datos SQLite para
añadir persistencia de datos a tus desarrollos Android.
¿Qué Es SQLite?
Es un ligero motor de bases de datos de código abierto, que se caracteriza por
mantener el almacenamiento de información persistente de forma sencilla.
Es por eso que SQLite es una tecnología cómoda para los dispositivos móviles.
Su simplicidad, rapidez y usabilidad permiten un desarrollo muy amigable.
Refuerza tus conocimientos en diseño de base de datos con el ebook
Metodología para diseño conceptual de bases de datos de Hermosa
Programación.
Ejemplo Base De Datos SQLite: Lawyers App
Lawyers App es un pequeño ejemplo que demuestra cómo crear una aplicación
Android con bases de datos relacionales.
Su función es servir como plataforma de persistencia para todos los abogados
de una compañía que presta servicios de asesoría a los usuarios.
Se compone de 3 screens:
▪ Lawyers: Contiene una lista con todos los abogados del gabinete.
▪ Lawyer Detail: Muestra el detalle de un abogado al presionar un ítem de
lista.
▪ Add/Edit Lawyer: Formulario con campos de texto para crear o modificar
un abogado.
▪
El siguiente es un wireframe que muestra los puntos de interacción:
Antes de iniciar, abre Android Studio y crea un proyecto llamado «Lawyers
App» con la siguiente configuración:
Con esto listo, procedamos a los pasos para implementar nuestra SQLite App.
Con SQLite no es diferente, por lo que debes crear un esquema predefinido para
implementarlo a la hora de crear tu base de datos.
La documentación de Android nos recomienda crear una clase
llamada Contract Class, la cual guarda como constantes todas las
características de la base de datos.
Para representarla crea un nuevo paquete Java con el nombre data. Dentro de
este, añade una clase llamada Lawyer.
Lawyer.java
/**
* Entidad "abogado"
*/
public class Lawyer {
private String id;
private String name;
private String specialty;
private String phoneNumber;
private String bio;
private String avatarUri;
Añade dentro del paquete data una nueva clase llamada LawyersContract y
define una clase interna con los datos de la tabla "lawyer" que se creará en la
base de datos:
LawyersContract.java
/**
* Esquema de la base de datos para abogados
*/
public class LawyersContract {
La clase que nos permitirá comunicar nuestra aplicación con la base de datos
se llama SQLiteOpenHelper. Se trata de una clase abstracta que nos provee los
mecanismos básicos para la relación entre la aplicación Android y la
información.
Para implementar este controlador debes:
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// Comandos SQL
}
/data/data/<paquete>/databases/<nombre-de-la-bd>.db
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// No hay operaciones
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("CREATE TABLE " + LawyerEntry.TABLE_NAME + " ("
+ LawyerEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ LawyerEntry.ID + " TEXT NOT NULL,"
+ LawyerEntry.NAME + " TEXT NOT NULL,"
+ LawyerEntry.SPECIALTY + " TEXT NOT NULL,"
+ LawyerEntry.PHONE_NUMBER + " TEXT NOT NULL,"
+ LawyerEntry.BIO + " TEXT NOT NULL,"
+ LawyerEntry.AVATAR_URI + " TEXT,"
+ "UNIQUE (" + LawyerEntry.ID + "))");
Este método ejecuta una sola sentencia SQL que no retorne en filas. Por lo que
el comando SELECT no es posible usarlo dentro de él.
Ejemplo…
@Override
public void onCreate(SQLiteDatabase db) {
// Create table...
// Contenedor de valores
ContentValues values = new ContentValues();
// Pares clave-valor
values.put(LawyerEntry.ID, "L-001");
values.put(LawyerEntry.NAME, "Carlos solarte");
values.put(LawyerEntry.SPECIALTY, "Abogado penalista");
values.put(LawyerEntry.PHONE_NUMBER, "300 200 1111");
values.put(LawyerEntry.BIO, "Carlos es una profesional con 5 años de
trayectoria...");
values.put(LawyerEntry.AVATAR_URI, "carlos_solarte.jpg");
// Insertar...
db.insert(LawyerEntry.TABLE_NAME, null, values);
return sqLiteDatabase.insert(
LawyerEntry.TABLE_NAME,
null,
lawyer.toContentValues());
Podrías usar el comando execSQL() para ejecutar una sentencia INSERT, pero
como estás recibiendo datos externos, es mejor usar insert() para evitar
inyecciones SQL.
@Override
public void onCreate(SQLiteDatabase db) {
// create table
Cursor c = db.query(
LawyerEntry.TABLE_NAME, // Nombre de la tabla
null, // Lista de Columnas a consultar
null, // Columnas para la cláusula WHERE
null, // Valores a comparar con las columnas del WHERE
null, // Agrupar con GROUP BY
null, // Condición HAVING para GROUP BY
null // Cláusula ORDER BY
);
Este método te ayuda a añadir todas las partes posibles de las cuales se podría
componer una consulta, además que te protege de inyecciones SQL, separando
las cláusulas de los argumentos.
Cursor c = db.query(
LawyerEntry.TABLE_NAME,
columns,
selection,
selectionArgs,
null,
null,
null
);
Ahora, existe otro método alternativo para realizar consultas
llamado rawQuery(). Con él pasas como parámetro un String del código SQL de
la consulta.
Veamos:
Cursores en SQLite
Tanto query() como rawQuery() retornan un objeto de tipo Cursor.
Este objeto es un apuntador al conjunto de valores obtenidos de la consulta. Al
inicio el cursor apunta a una dirección previa a la primera fila. Por lo que
debes leer cada tupla moviendo el cursor a la fila siguiente.
while(c.moveToNext()){
String name = c.getString(c.getColumnIndex(LawyerEntry.NAME));
// Acciones...
}
Usa métodos get*() para obtener el valor de cada columna a través del índice
según su tipo de dato. Es decir, obtienes enteros con getInt(), flotantes
con getFloat(), etc.
El índice de la columna se obtiene con getColumnsIndex().
Leer abogados de la base de datos
Puedes aprovechar este nuevo concepto e implementar un método de lectura
para todos los abogados (getAllLawyers()) y otro por ID (getLawyerById()).
La diferencia estaría en la lectura por id requiere ese elemento como
parámetro…
public Cursor getAllLawyers() {
return getReadableDatabase()
.query(
LawyerEntry.TABLE_NAME,
null,
null,
null,
null,
null,
null);
}
activity_lawyers.xml
<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>
<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:tint="@android:color/white"
app:fabSize="normal"
app:srcCompat="@drawable/ic_account_plus" />
</android.support.design.widget.CoordinatorLayout>
content_lawyers.xml
Abre el código prefabricado que te aparezca y límpialo para que te quede así:
LawyersFragment.java
/**
* Vista para la lista de abogados del gabinete
*/
public class LawyersFragment extends Fragment {
public LawyersFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_lawyers, container,
false);
return root;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".lawyers.LawyersFragment">
<ListView
android:id="@+id/lawyers_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"/>
</FrameLayout>
Si retomas el wireframe visto al inicio del tutorial, verás que la foto de perfil
del abogado está al lado izquierdo de la distribución y justo a su derecha va el
nombre completo.
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="72dp"
android:text="New Text"
android:textAppearance="?textAppearanceListItem"
tools:text="Carlos Giron" />
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_account_circle" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lawyers);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportFragmentManager().findFragmentById(R.id.lawyers_container);
if (fragment == null) {
fragment = LawyersFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.lawyers_container, fragment)
.commit();
}
}
}
Adaptador de abogados
/**
* Adaptador de abogados
*/
public class LawyersCursorAdapter extends CursorAdapter {
2. Agrega un constructor que transmita los parámetros a través de super para
mantener la herencia.
@Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
LayoutInflater inflater = LayoutInflater.from(context);
return inflater.inflate(R.layout.list_item_lawyer, viewGroup, false);
}
@Override
public void bindView(View view, final Context context, Cursor cursor) {
// Referencias UI.
TextView nameText = (TextView) view.findViewById(R.id.tv_name);
final ImageView avatarImage = (ImageView) view.findViewById(R.id.iv_avatar);
// Get valores.
String name = cursor.getString(cursor.getColumnIndex(LawyerEntry.NAME));
String avatarUri =
cursor.getString(cursor.getColumnIndex(LawyerEntry.AVATAR_URI));
// Setup.
nameText.setText(name);
Glide
.with(context)
.load(Uri.parse("file:///android_asset/" + avatarUri))
.asBitmap()
.error(R.drawable.ic_account_circle)
.centerCrop()
.into(new BitmapImageViewTarget(avatarImage) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable drawable
=
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
drawable.setCircular(true);
avatarImage.setImageDrawable(drawable);
}
});
El singleton Glide hace parte de una librería con el mismo nombre, cuyo
objetivo es cargar imágenes de forma eficiente.
Por ejemplo…
Solución
Usa el layout del sistema two_line_list_item en el constructor del adaptador:
//Iniciando el nuevo Adaptador
mLawyersAdapter = new SimpleCursorAdapter(
getActivity(), // Context context
android.R.layout.two_line_list_item, // int layout
mLawyersDbHelper.getAllLawyers(), // Cursor c
new String[]{LawyerEntry.NAME, LawyerEntry.SPECIALTY}, // String[] from
new int[]{android.R.id.text1, android.R.id.text2}, // int[] to
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER // int flags
);
mLawyersList.setAdapter(mLawyersAdapter);
public LawyersFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_lawyers, container, false);
// Referencias UI
mLawyersList = (ListView) root.findViewById(R.id.lawyers_list);
mLawyersAdapter = new LawyersCursorAdapter(getActivity(), null);
mAddButton = (FloatingActionButton) getActivity().findViewById(R.id.fab);
// Setup
mLawyersList.setAdapter(mLawyersAdapter);
// Instancia de helper
mLawyersDbHelper = new LawyersDbHelper(getActivity());
// Carga de datos
loadLawyers();
return root;
}
private void loadLawyers() {
// Cargar datos...
}
2. Crea una tarea asíncrona dentro del fragmento, la cuál reciba como
resultado un Cursor. Esto con el fin de no entorpecer el hilo principal con el
acceso a la base de datos.
@Override
protected Cursor doInBackground(Void... voids) {
return mLawyersDbHelper.getAllLawyers();
}
@Override
protected void onPostExecute(Cursor cursor) {
if (cursor != null && cursor.getCount() > 0) {
mLawyersAdapter.swapCursor(cursor);
} else {
// Mostrar empty state
}
}
}
LawyersActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lawyers);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportFragmentManager().findFragmentById(R.id.lawyers_container);
if(fragment==null){
fragment = LawyersFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.lawyers_container, fragment)
.commit();
}
}
}
Debido a que se usará scroll con la foto de perfil del abogado, incluye un
elemento <ImageView> por encima de la toolbar.
activity_lawyer_detail.xml
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.NestedScrollView>
LawyerDetailFragment.java
/**
* Vista para el detalle del abogado
*/
public class LawyerDetailFragment extends Fragment {
public LawyerDetailFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mLawyerId = getArguments().getString(ARG_LAWYER_ID);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_lawyer_detail, container,
false);
mCollapsingView = (CollapsingToolbarLayout)
getActivity().findViewById(R.id.toolbar_layout);
mAvatar = (ImageView) getActivity().findViewById(R.id.iv_avatar);
mPhoneNumber = (TextView) root.findViewById(R.id.tv_phone_number);
mSpecialty = (TextView) root.findViewById(R.id.tv_specialty);
mBio = (TextView) root.findViewById(R.id.tv_bio);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Acciones
}
El wireframe inicial mostraba la foto de perfil del abogado en la app bar y por
debajo una serie de pares etiqueta-contenido con los demás datos.
Basado en esa idea, intenta recrear el siguiente mock con la organización que
desees:
En mi caso el resultado final me quedó así:
fragment_lawyer_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="72dp"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:text="Teléfono"
android:textColor="?colorPrimary" />
<TextView
android:id="@+id/tv_phone_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="300 20 1111" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:text="Especialidad"
android:textColor="?colorPrimary" />
<TextView
android:id="@+id/tv_specialty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="Abogado penalista" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:text="Biografía"
android:textColor="?colorPrimary" />
<TextView
android:id="@+id/tv_bio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="@string/large_text" />
</LinearLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lawyer_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
String id = getIntent().getStringExtra(LawyersActivity.EXTRA_LAWYER_ID);
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_lawyer_detail, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// más...
loadLawyer();
return root;
}
@Override
protected Cursor doInBackground(Void... voids) {
return mLawyersDbHelper.getLawyerById(mLawyerId);
}
@Override
protected void onPostExecute(Cursor cursor) {
if (cursor != null && cursor.moveToLast()) {
showLawyer(new Lawyer(cursor));
} else {
showLoadError();
}
}
// Eventos
mLawyersList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l)
{
// ...
}
});
showDetailScreen(currentLawyerId);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (Activity.RESULT_OK == resultCode) {
switch (requestCode) {
case REQUEST_UPDATE_DELETE_LAWYER:
loadLawyers();
break;
}
}
}
La Herramienta sqlite3
sqlite3 es una herramienta de administración para nuestras bases de datos
SQLite a través de la línea de comandos. Normalmente puedes descargarla de
la página oficial de SQLite, pero tanto como la distribución de Android y
Android Studio ya la traen consigo.
<sdk>/platform-tools/
Recuerda que para navegar a través de carpetas en DOS se utiliza el
comando cd.
3. Una vez hayas encontrado el directorio, digita la siguiente linea de
comandos:
adb shell
root@android:/ #
sqlite3 data/data/<package>/databases/<nombre-base-de-datos>
2. Luego usa .open para abrir el archivo en una ruta especificada o copia y
pega el archivo Lawyers.db en la carpeta:
sqlite>.open Lawyers.db
3. Finalmente usa .schema y tendrás el mismo resultado anterior.
db.delete(
LawyerEntry.TABLE_NAME,
selection,
selectionArgs);
Eliminar un abogado
La eliminación y edición van como action buttons en la Toolbar de la
actividad de detalle.
1. Para agregarlos ve a res/menu y abre menu_lawyer_detail.xml.
Agrega dos nodos <item>. El primero con el título de edición y el segundo
refiriendose a la eliminación.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".lawyerdetail.LawyerDetailActivity">
<item
android:id="@+id/action_edit"
android:orderInCategory="1"
android:title="@string/action_edit"
android:icon="@drawable/ic_pencil"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_delete"
android:orderInCategory="2"
android:icon="@drawable/ic_delete"
android:title="@string/action_delete"
app:showAsAction="ifRoom" />
</menu>
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
setHasOptionsMenu(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
showEditScreen();
break;
case R.id.action_delete:
new DeleteLawyerTask().execute();
break;
}
return super.onOptionsItemSelected(item);
}
4. Para manejar el evento de borrado, crea una nueva tarea asíncrona que
llame a DeleteLawyerTask.
@Override
protected void onPostExecute(Integer integer) {
showLawyersScreen(integer > 0);
}
▪ Nombre de la tabla
▪ Valores nuevos
▪ Instrucción WHERE
▪ Argumentos del WHERE
Por ejemplo…
// Valores
ContentValues values = new ContentValues();
// WHERE
String selection = LawyerEntry.ID + " LIKE ?";
String[] selectionArgs = {"L-009"};
// Actualizar
db.update(
LawyerEntry.TABLE_NAME,
values,
selection,
selectionArgs);
Actualizar abogados
Dentro de LawyersDbHelper crea un nuevo método llamado updateLawyer(),
cuyos parámetros sean un objeto Lawyer y un string con el ID a modificar.
Su propósito es convertir el POJO en ContentValues y luego llamar a update():
<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>
<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:tint="@android:color/white"
app:fabSize="normal"
app:srcCompat="@drawable/ic_check" />
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
AddEditLawyerFragment.java
/**
* Vista para creación/edición de un abogado
*/
public class AddEditLawyerFragment extends Fragment {
private static final String ARG_LAWYER_ID = "arg_lawyer_id";
public AddEditLawyerFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mLawyerId = getArguments().getString(ARG_LAWYER_ID);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_add_edit_lawyer,
container, false);
// Referencias UI
mSaveButton = (FloatingActionButton)
getActivity().findViewById(R.id.fab);
mNameField = (TextInputEditText) root.findViewById(R.id.et_name);
mPhoneNumberField = (TextInputEditText)
root.findViewById(R.id.et_phone_number);
mSpecialtyField = (TextInputEditText)
root.findViewById(R.id.et_specialty);
mBioField = (TextInputEditText) root.findViewById(R.id.et_bio);
mNameLabel = (TextInputLayout) root.findViewById(R.id.til_name);
mPhoneNumberLabel = (TextInputLayout)
root.findViewById(R.id.til_phone_number);
mSpecialtyLabel = (TextInputLayout)
root.findViewById(R.id.til_specialty);
mBioLabel = (TextInputLayout) root.findViewById(R.id.til_bio);
// Eventos
mSaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addEditLawyer();
}
});
// Carga de datos
if (mLawyerId != null) {
loadLawyer();
}
return root;
}
fragment_add_edit_lawyer.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
android:orientation="vertical"
tools:context=".addeditlawyer.AddEditLawyerFragment">
<android.support.design.widget.TextInputLayout
android:id="@+id/til_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nombre"
android:inputType="textPersonName"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
tools:text="Alejandro Riascos" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Número de teléfono"
android:inputType="phone"
tools:text="300 200 4564" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_specialty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_specialty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Especialidad"
android:inputType="text"
tools:text="Abogado penalista" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/til_bio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_bio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top|start"
android:hint="Biografía"
android:imeOptions="actionDone"
android:inputType="text|textMultiLine"
tools:text="@string/lorem" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
AddEditLawyerActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_edit);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
String lawyerId =
getIntent().getStringExtra(LawyersActivity.EXTRA_LAWYER_ID);
getSupportFragmentManager().findFragmentById(R.id.add_edit_lawyer_container);
if (addEditLawyerFragment == null) {
addEditLawyerFragment = AddEditLawyerFragment.newInstance(lawyerId);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.add_edit_lawyer_container, addEditLawyerFragment)
.commit();
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
Guardar/Modificar abogado
// Eventos
mSaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addEditLawyer();
}
});
@Override
protected Boolean doInBackground(Lawyer... lawyers) {
if (mLawyerId != null) {
return mLawyersDbHelper.updateLawyer(lawyers[0], mLawyerId) > 0;
} else {
return mLawyersDbHelper.saveLawyer(lawyers[0]) > 0;
}
@Override
protected void onPostExecute(Boolean result) {
showLawyersScreen(result);
}
}
Muestra la actividad de abogados en onPostExecute() con un nuevo método
llamado showLawyersScreen(). Setea el resultado de la actividad dependiendo
del comportamiento de la tarea asíncrona:
getActivity().finish();
}
if (TextUtils.isEmpty(name)) {
mNameLabel.setError(getString(R.string.field_error));
error = true;
}
if (TextUtils.isEmpty(phoneNumber)) {
mPhoneNumberLabel.setError(getString(R.string.field_error));
error = true;
}
if (TextUtils.isEmpty(specialty)) {
mSpecialtyLabel.setError(getString(R.string.field_error));
error = true;
}
if (TextUtils.isEmpty(bio)) {
mBioLabel.setError(getString(R.string.field_error));
error = true;
}
if (error) {
return;
}
new AddEditLawyerTask().execute(lawyer);
mAddButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showAddScreen();
}
});
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (Activity.RESULT_OK == resultCode) {
switch (requestCode) {
case AddEditLawyerActivity.REQUEST_ADD_LAWYER:
showSuccessfullSavedMessage();
loadLawyers();
break;
case REQUEST_UPDATE_DELETE_LAWYER:
loadLawyers();
break;
}
}
}
El mensaje sería:
Conclusión
Hasta aquí ya tienes claro cómo usar una base de datos SQLite sencilla en
Android.
Viste como usar una clase tipo contrato para estandarizar la estructura de las
tablas y columnas.
Ya sabes que existen herramientas como sqlite3 y SQLite Browser para editar y
visualizar tu modelo de datos.