ALMACENAMIENTO DE DATOS
GESTIÓN DE FICHEROS
Lo primero que hay que tener en cuenta es dónde queremos almacenar los ficheros y el
tipo de acceso que queremos tener a ellos. Así, podremos leer y escribir ficheros
localizados en:
1. La memoria interna del dispositivo.
2. La tarjeta SD externa, si existe.
3. La propia aplicación, en forma de recurso.
Ficheros en Android: Almacenados en la propia app
Estos ficheros se almacenan como recursos de la propia app y se crean durante el
desarrollo de la misma, en la carpeta /res/raw (es posible que no exista esta carpeta y
toque crearla). El problema es que solo podremos leer estos ficheros, nunca crear nuevos
en tiempo de ejecución, ni sobrescribir los existentes, por tanto, se suele usar en casos
muy concretos.
Pasos:
1. Crea la carpeta res/raw pulsando con el botón derecho encima de la carpeta res –
new – Android Resource Directory y selecciona como Resource type “raw”.
Dejamos lo demás por defecto y pulsamos ok.
2. Crear con el bloc de notas, un fichero, con el nombre [Link], y el texto
“Hola Mundo!!” y guardar en la carpeta raw del proyecto.
3. Para leer el fichero, al estar guardado como recurso, tenemos que hacer uso del
método getResources, para acceder a estos recursos y ejecutar el método
openRawResource(idFichero). Añade dentro del case [Link].btn_app_storage del
método onClick:
InputStream is = getResources().openRawResource([Link]);
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
try {
String texto = [Link]();
[Link](this, texto, Toast.LENGTH_SHORT).show();
}catch (Exception e){
[Link](this, "Error leyendo fichero raw",
Toast.LENGTH_SHORT).show();
}
break;
4. En el código podemos ver que el método openRawResource nos devuelve un
InputStream que ya podemos leer creando un buffer de lectura propio de java.
Fíjate, que hemos puesto el método readLine entre un try-catch ya que puede dar
una IOException si se produce algún error durante la lectura. Si esta todo correcto,
mostramos un toast con el texto del fichero, o en caso de error, mostramos un
Toast con un mensaje de error.
5. Ejecutar la app, pulsar en el botón “Fichero Recursos” y comprobar el resultado.
Ficheros en Android: Memoria interna
Para obtener un fichero, haremos uso de la clase File, que recibe como parámetros, la
ruta donde está o estará el fichero y su nombre.
Por ejemplo: File file = new File(“/data/data/[Link]/files/”,”[Link]”);
Escritura
Para escribir en la memoria interna, Android nos proporciona la clase FileWriter, a la que
le pasamos como parámetro el fichero creado. Vamos a verlo mas claro con el código:
1. Añade esta línea al principio de la clase MainActivity, para referenciar al nombre
del fichero.
private static final String INTERNAL_FILENAME = "[Link]";
2. Añade dentro del case [Link].btn_save_internal_storage:
File wFile = new File(getFilesDir(), INTERNAL_FILENAME);
try{
FileWriter out = new FileWriter(wFile);
[Link]([Link]().toString());
[Link]();
}catch (IOException e){
[Link](this, "Error escribiendo fichero en memoria interna",
Toast.LENGTH_SHORT).show();
}
break;
La clase File recibe la ruta y el nombre del fichero. Para la ruta, usamos el método
getFilesDir(), que nos devuelve la ruta de la carpeta para ficheros de la memoria
interna, y como nombre, usamos la constante que hemos creado en el paso
anterior.
Una vez tenemos el fichero, creamos un FileWriter para poder escribir en el,
escribimos el texto que hemos añadido en el EditText y por último lo cerramos.
Lectura
Una vez ya hemos leído un fichero de los recursos y hemos escrito en la memoria interna,
usaremos la clase File para recuperar el fichero creado y después gastaremos un buffer
de lectura, igual que en el caso de la lectura del fichero de recursos, para leer su
contenido.
Añade en el case [Link].btn_read_internal_storage:
File rFile = new File(getFilesDir(), INTERNAL_FILENAME);
try{
BufferedReader bReader = new BufferedReader(new FileReader(rFile));
String textRead = [Link]();
[Link](this, textRead, Toast.LENGTH_SHORT).show();
} catch (IOException e){
[Link](this, "Error leyendo fichero de memoria interna",
Toast.LENGTH_SHORT).show();
}
break;
Ficheros en Android: Memoria externa
La gran diferencia entre la memoria interna y externa, es que la externa puede verla
cualquiera con un explorador de ficheros, mientras que la interna, solo será accesible por
la app (siempre que no seas root). Otra característica de la memoria externa, es que está
dividida en 2:
Interna de la app: Que se accede por el método getExternalFilesDir y se situa en
“directorio_mem_externa/Android/data/paqueteapp/files”. Se borrará cuando se desintale
la app.
Pública: Se accede por el método estático getExternalStoragePublicDirectory de la clase
Environment y a diferencia de la anterior, esta no se borra cuando desinstalamos la app,
por tanto, es apropiada, por ejemplo, para apps de fotos o similares que quieran preservar
los ficheros aunque la desinstalemos. Esta situada en
“directorio_mem_externa/tipocarpetaelegido/”.
Además, puede que esta memoria no este disponible, por tanto, conviene asegurarse,
haciendo uso del método estático getExternalStorageState, también incluido en la clase
Environment. Copia estos 2 métodos en la actividad para facilitar su uso:
public boolean isExternalStorageWritable() {
String state = [Link]();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public boolean isExternalStorageReadable() {
String state = [Link]();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Por último, necesitamos pedir permiso de escritura para la memoria externa. Para ello,
antes de empezar añade en el manifest la siguiente línea:
<uses-permission
android:name="[Link].WRITE_EXTERNAL_STORAGE"/>
Escritura
Escribir en la memoria externa, es practicamente idéntico a hacerlo en la interna, con la
diferencia de que tenemos que comprobar que este disponible y cambiar la ruta al crear el
File, dependiendo si queremos que sea la asociada a la app (getExternalFilesDir ) o la
pública (getExternalStoragePublicDirectory ). Vamos a verlo más claro en el código:
1. Añade esta línea al principio de la clase MainActivity, para referenciar al nombre
del fichero: private static final String EXTERNAL_FILENAME = "[Link]";
2. Añade dentro del case [Link].btn_save_sd:
if(isExternalStorageWritable()) {
// File wFileE = new
File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
EXTERNAL_FILENAME);
File wFileE = new
File([Link](Environment.DIRECTORY_D
OWNLOADS), EXTERNAL_FILENAME);
try {
FileWriter out = new FileWriter(wFileE);
[Link]([Link]().toString());
[Link]();
} catch (IOException e) {
[Link](this, "Error escribiendo fichero en memoria
externa", Toast.LENGTH_SHORT).show();
}
}
break;
Los métodos getExternalFilesDir y getExternalStoragePublicDirectory, a diferencia de
getFilesDir, reciben como parámetro, la subcarpeta en la que queremos guardar el
fichero, dependiendo de su tipo. Android aconseja el uso de estas divisiones para que el
sistema pueda identificar el tipo de ficheros y mostrarlos cuando sea necesario. Por
ejemplo, los archivos guardados en el ejemplo, se guardarán en una subcarpeta llamada
DOWNLOADS. Si fueran imagenes, y marcáramos
Environment.DIRECTORY_PICTURES, se crearía una subcarpeta PICTURES y las fotos
aparecerían en la galería del teléfono.
Lectura
Añade en el case [Link].btn_read_sd:
if(isExternalStorageReadable()) {
// File rFileE = new
File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
EXTERNAL_FILENAME);
File rFileE = new
File([Link](Environment.DIRECTORY_DOWNL
OADS), EXTERNAL_FILENAME);
try {
BufferedReader bReader = new BufferedReader(new FileReader(rFileE));
String textRead = [Link]();
[Link](this, textRead, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
[Link](this, "Error leyendo fichero de memoria externa",
Toast.LENGTH_SHORT).show();
}
}
USO DE BASE DE DATOS
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. A diferencia de otros
Sistemas gestores de bases de datos como MySQL, SQL Server y Oracle DB, SQLite
tiene las siguientes ventajas:
No requiere el soporte de un servidor: SQLite no ejecuta un proceso para administrar la
información, si no que implementa un conjunto de librerías encargadas de la gestión.
No necesita configuración: Libera al programador de todo tipo de configuraciones de
puertos, tamaños, ubicaciones, etc.
Usa un archivo para el esquema: Crea un archivo para el esquema completo de una
base de datos, lo que permite ahorrarse preocupaciones de seguridad, ya que los datos
de las aplicaciones Android no pueden ser accedidos por contextos externos.
Es de Código Abierto: Está disponible al dominio público de los desarrolladores al igual
que sus archivos de compilación e instrucciones de escalabilidad. 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.
Una vez que estemos en nuestro proyecto crearemos una nueva clase la cual debe de
extender de SQLiteOpenHelper. Esta clase se encuentra en [Link] así
que debemos de importarla, en este caso la clase se llamará EjemploDB.
Una vez que tenemos nuestra clase heredando de SQLiteOpenHelper necesitaremos
agregar dos nuevos métodos:
El primero un método llamado onCreate el cual recibe como parámetro un objeto
SQLIteDatabase.
El segundo método onUpgrade que recibe como parámetros un objeto SQLiteDatabase y
dos enteros (Este método profundizaremos más a detalle en otro post).
Los métodos quedaran de la siguiente manera:
public void onCreate(SQLiteDatabase db) {
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
}
Dentro de nuestra clase crearemos dos nuevas variables estáticas para poder administrar
de mejor manera nuestra base de datos:
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "[Link]";
Como podemos observar una variable nos permitirá llevar un control del número de
versión correspondiente a nuestra base de datos y la otra almacena el nombre de nuestra
base de datos. Para ir concluyendo los preparativos de nuestra clase dentro de nuestro
constructor debemos indicarle que espera como parámetro un objeto de tipo Context,
dentro de este mismo debemos llamar la constructor de la clase de la cual heredamos
(SQLiteOpenHelper ), pasándole como parámetros el contexto, el nombre de nuestra
base de datos, un cursor Factory (para este tutorial será null) y una versión, en mi caso
quedaría así:
public EjemploDB(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
Lo que corresponde ahora es crear la base de datos y para ellos debemos hacerlo en
nuestro método onCreate, sin embargo primero debemos de establecer nuestras
columnas de nuestra tabla, para una administración más fácil la documentación de
android nos coloca en su ejemplo establecer los nombres de las tablas mediante
atributos de una interfaz.
Dentro de nuestra clase (EjemploDB ) colocaremos el nombre de nuestra tabla ( o tablas)
y los nombres de nuestras columnas mediante variables de tipo String staticas :
public static final String TABLA_NOMBRES = "nombres";
public static final String COLUMNA_ID = "_id";
public static final String COLUMNA_NOMBRE = "nombre";
Con estas tres variables nos podemos dar una idea clara de que tendremos una tabla
llamada nombres la cual tendrá dos columnas, una columna _id y una nombre. Para la
creación de nuestra base de datos debemos realizarla mediante una sentencia SQL, de
igual forma es recomendable establecer esta sentencia en una variable:
private static final String SQL_CREAR = "create table "
+ TABLA_NOMBRES + "(" + COLUMNA_ID
+ " integer primary key autoincrement, " + COLUMNA_NOMBRE
+ " text not null);";
Ya tenemos el nombre de nuestra tabla, las columnas y la sentencia ahora es el momento
de ejecutarlo. A nuestro método onCreate debe quedar de la siguiente manera:
public void onCreate(SQLiteDatabase db) {
[Link](SQL_CREAR);
}
Con esto indicamos que nuestra base de datos debe ejecutar una sentencia SQL, que en
nuestro caso la encontramos almacenada en la variable SQL_CREAR.
Create:
Para comenzar a utilizar nuestra base de datos vamos a crear un método llamado agregar
que recibe como parámetro un objeto String( el nombre ). El método quedaría de la
siguiente manera:
public void agregar(Stringnombre){
SQLiteDatabase db = [Link]();
ContentValues values = new ContentValues();
[Link](COLUMNA_NOMBRE, nombre);
[Link](TABLA_NOMBRES, null,values);
[Link]();
}
Lo primero que hacemos es indicarle a la clase que vamos a hacer uso de la base de
datos, lo segundo es crear un objeto ContentValues el cual nos ayudara a almacenar de
manera temporal nuestros datos relacionándolos a la columna a la cual pertenecen (en
este caso nombre a la columna nombre), ya por ultimo le indicamos a la base de datos
que deseamos insertar un nuevo elemento para ello utilizamos su método insert. Con este
método ya podemos almacenar datos en nuestra tabla.
Read:
Para poder extraer los datos crearemos otro método, el método se nombrara obtener.
Este método tendrá ciertas peculiaridades que no es necesario que comprendas en estos
momentos y son temas que se tocarán en otro momento.
public void obtener(int id){
SQLiteDatabase db = [Link]();
String[] projection = {COLUMNA_ID, COLUMNA_NOMBRE};
Cursor cursor =
[Link](TABLA_NOMBRES,
projection,
" _id = ?",
new String[] { [Link](id) },
null,
null,
null,
null);
if (cursor != null)
[Link]();
[Link]("El nombre es " + [Link](1) );
[Link]();
}
Para este método lo primero que debemos de hacer es indicarle a la clase que vamos a
utiliza la base datos (como en el método agregar), para el query de select debemos de
tener una proyección (nombre con que lo maneja la documentación) que no es más que
una arreglo de todas nuestras columnas con las cuales vamos a trabajar.
El método query recibe como parámetro principalmente el nombre de la tabla a utilizar, la
proyección, nuestra condicional para el select, en este caso la columna _id y con que
valor debe buscarlo, es por eso que vemos otra arreglo de string como parámetro, los
siguiente cuatro parámetros son para realizar un query más complejo. Para almacenar el
resultado de nuestra búsqueda debemos hacer mediante un objeto Cursor.
Para poder visualizar el nombre simplemente mandamos una impresión a consola
mediante System, incluso si nosotros así lo deseamos podemos regresar el valor o el
cursor.
Prueba:
Bien con esto dos métodos podemos probar si nuestro ejemplo se encuentra funcionando
de forma correcta, vamos a modificar nuestro método agregar y colocaremos dos líneas
de código más:
long newRowId;
newRowId = [Link](T…
Con esto vamos a poder conocer el id de nuestro dato almacenado, lo que falta ahora es
retornar ese valor, cambiamos nuestro método para regresar el valor (int) y colocamos:
return (int) newRowId;
Bien ahora probemos nuestro ejemplo:
EjemploDB db = new EjemploDB( getApplicationContext() );
int id = [Link]("Eddard Stark");
[Link](id);
[Link](id);
(No es necesario que visualicemos los resultados en consola, podemos apoyarnos de
nuestras vistas o de un Toast).
Update:
Para editar debemos de colocar este método:
public void actualizar (String nombre, int id){
SQLiteDatabase db = [Link]();
ContentValues values = new ContentValues();
[Link]("nombre",nombre);
int i = [Link](TABLA_NOMBRES,
values,
" _id = ?",
new String[] { [Link]( id ) });
[Link]();
}
El método actualizar espera como parámetro el nuevo nombre y el id de la tupla a
cambiar. Y como ya se nos está haciendo costumbre lo primero que debemos hacer es
obtener nuestra base de datos.
Al igual que con el método agregar debemos de almacenar nuestros valores en sus
respectivas columnas mediante un objeto ContentValues y con el método update de
nuestra base de datos establecemos que tabla queremos utilizar, los valores a cambiar
(con el objeto ContentValues) y la condicional para realizar el cambio (Al igual que en el
Select)
" _id = ?" nos indica que utilizaremos el campo id como referencia para saber que filas
serán actualizadas y con new String[] { [Link]( id ) }); indicamos el valor que debe
tener la columna.
Probamos el ejemplo:
[Link]("CatellyTully", 1);
[Link](1);
Con esto ya no obtendremos Eddard Stark si no Catelly Tully con lo cual confirmamos que
nuestro método actualizar funciona.
Delete: Toma partes de cada método utilizado anteriormente:
public boolean eliminar(int id) {
SQLiteDatabase db = [Link]();
try{
[Link](TABLA_NOMBRES,
" _id = ?",
new String[] { [Link] (id ) });
[Link]();
return true;
}catch(Exception ex){
return false;
}
}
Aquí simplemente agregamos un Try y un Catch por buenas practicas (También debemos
agregarlo en los otro métodos) y solo para no dejar un return true siempre.
Framework de desarrollo web
Existen framework que permite el desarrollo de aplicaciones nativas a partir de
aplicaciones desarrolladas con los lenguajes de desarrollo web, convirtiéndose en
aplicaciones híbridas.
AppCelerator: un framework que permite crear aplicaciones nativas para móviles
basándonos en Javascript. Además, no sólo incluye esto, sino automatización de test.
jQuery Mobile: Si anteriormente hablábamos de Javascript, en este caso hablamos de
HTML5, el cual nos permite escribir una sola versión del código para hacerlo funcionar en
diferentes plataformas.
CoronaSDK: Es muy fácil para adaptarse a él y sobre todo es utilizado en el ámbito de
los juegos. Eso no quita que se utilice para cualquier tipo de aplicación. Además, tiene
más de 500 APIs y soporte para interfaces nativas.
The App Builder: volvemos a HTML5, el cual nos ofrece una interfaz sin código para
desarrollar más rápido. Además, uno de sus aspectos más interesantes es que nos
permite publicar directamente una aplicación en Google Play.
PhoneGap: Este framework, esponsorizado por Adobe y Apache, nos permite crear
aplicaciones multiplataforma que soporte HTML5, CSS y JavaScript, permitiendo incluso
embebir este código en aplicaciones para acceder a determinado hardware del
dispositivo.
Xamarin: nos permitirá generar nuestra aplicación para iOS (.APP) y para Android (.APK),
la cual ya sí correrá de forma nativa. Gracias a esto, surge una de las grandes ventajas de
Xamarin: la reutilización de código.
OPTIMIZACIÓN DEL CÓDIGO Y BUENAS PRÁCTICAS
Evitar concatenaciones de Strings, utilizar StringBuffer o StringBuilder para tal
caso. La concatenación de Strings produce cada vez un nuevo objeto y por tanto,
mayor consumo de memoria y mayor recolección de basura. (Por favor, esta
hacedla siempre)
La encriptación y conexiones https tienen peor rendimiento.
Crear métodos con el menor número de parámetros posible. Esta es de primero de
SOLID.
Si se van a realizar operaciones complejas como, senos, cosenos u otras
operaciones complicadas de coma flotante y se sabe de antemano cuál va a ser el
resultado, es conveniente pre-calcular estos valores y utilizarlos como constantes.
Soportar el trabajo off-line siempre que sea posible persistiendo la información en
el almacenamiento del dispositivo.
Sacar fuera de los bucles las constantes y creación de nuevos objetos
Siempre que vayamos a acceder a la misma posición de un array varias veces, es
mejor guardar esa posición en una variable local y así evitar el acceso repetido al
índice del array.
Delegar operaciones demasiado complejas en portales y acceder a los resultados
a través de servicios web o conexiones de red.
Liberar recursos tan pronto como sea posible, como conexiones de red, a streams
o a ficheros. Normalmente, se suele liberar este tipo de recursos dentro de la
cláusula finally para asegurarnos de que los recursos se liberan aún cuando se
produzca alguna excepción.
Hacer lo más ligera posible: Una interfaz fácil de usar brinda muchos beneficios,
pero para aprovechar al máximo la aplicación desarrollada, es necesario que no
exija demasiado al dispositivo. Las descargas de tamaños inmanejables, el uso
exagerado de recursos y el pedido de permisos innecesarios son barreras que
dificultan la adopción o la continuidad de uso
Referencias
Alvarez, M. A. (2 de Enero de 2014). ¿Qué es MVC? Obtenido de desarrolloweb:
[Link]
AppInventor. (s.f.). Componentes de sensores. Obtenido de Aprende App Inventor:
[Link]
sensores
cakephp. (s.f.). Entendiendo el Modelo - Vista - Controlador. Obtenido de cakephp:
[Link]
[Link]
CURSO DE DESARROLLO ANDROID. (s.f.). Obtenido de MovilZona:
[Link]
tema-4-conceptos-basicos-a-tener-en-cuenta-para-empezar-a-desarrollar-en-android/
ejemplosTIW. (s.f.). Patrón de arquitectura Modelo Vista Controlador (MVC). Obtenido de
ejemplosTIW: [Link]
fgallego. (s.f.). PROTOCOLOS Y FUNCIONALIDAD DE LA CAPA DE APLICACIÓN. Obtenido de utp:
[Link]
Oracle. (s.f.). Modelo de arquitectura del protocolo TCP/IP. Obtenido de Oracle:
[Link]
Patricia. (27 de Febrero de 2014). CURSO: Introducción a Android y entorno de desarrollo LECCIÓN
4: Arquitectura de Android. Obtenido de Mente Inquieta:
[Link]
Pérez, E. I. (20 de Junio de 2016). Bases de datos con android. Obtenido de Código Facilito:
[Link]
QUINTANILLA, J. A. (2013). ARQUITECTURA DE DISPOSITIVOS MOVILES. Obtenido de Academia:
[Link]
Revelo, J. (26 de Marzo de 2015). Crear Un Web Service Para Android Con Mysql, Php y Json.
Obtenido de Hermosa Programación:
[Link]
mysql-php-y-json/
Romeu, A. (2 de Enero de 2014). 25 buenas prácticas para optimizar código Java para Android.
Obtenido de El blog del informático: [Link]
android/
Simarro, I. G. (5 de Junio de 2015). Ficheros en Android. Obtenido de isgarsi:
[Link]
SlashMobility. (31 de Abril de 2011). Desarrollo de apps Android basadas en localización. Obtenido
de slideshare: [Link]
en-localizacin
UniversidadDeAlicante. (26 de Enero de 2014). Sensores y eventos. Obtenido de jtech:
[Link]