Bienvenidos sean a este post, en nuestro post anterior hemos comenzado la creacion la aplicacion para el ContentProvider, para el caso de hoy crearemos una nueva clase a la cual llamaremos PuntuacionesProvider donde reemplazaremos el codigo generado por el siguiente:

package org.example.puntuacionesprovider;

import android.content.ContentProvider;
import android.content.UriMatcher;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class PuntuacionesProvider extends ContentProvider {

    public static final String AUTORIDAD =
            "org.example.puntuacionesprovider";
    public static final Uri CONTENT_URI = Uri.parse("content://"
            + AUTORIDAD + "/puntuaciones");
    public static final int TODOS_LOS_ELEMENTOS = 1;
    public static final int UN_ELEMENTO = 2;
    private static UriMatcher URI_MATCHER = null;
    static {
        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
        URI_MATCHER.addURI(AUTORIDAD,"puntuaciones",TODOS_LOS_ELEMENTOS);
        URI_MATCHER.addURI(AUTORIDAD,"puntuaciones/#",UN_ELEMENTO);
    }

    public static final String TABLA = "puntuaciones";
    private SQLiteDatabase baseDeDatos;

    @Override
    public boolean onCreate(){
        PuntuacionesSQLiteHelper dbHelper = new
                PuntuacionesSQLiteHelper(getContext());
        baseDeDatos = dbHelper.getWritableDatabase();
        return baseDeDatos != null && baseDeDatos.isOpen();
    }
}

En este caso extenderemos a ContentProvider, nuestro siguiente paso sera la creacion de cuatro constantes de tipo publica y una constante de tipo privada, la primera almacenara la autoridad es decir el nombre del paquete, la segunda constante almacenara el contenido de tipo URI, es decir el nombre del paquete (AUTORIDAD) y seguido del path, la tercera constante se llamara TODOS_LOS_ELEMENTOS y tendra el valor de 1, la siguiente sera UN_ELEMENTO y tendra el valor 2 y la ultima constante sera URI_MATCHER que sera de tipo privada y tendra un valor null, el siguiente bloque se encargara de agregar contenido URI a URI_MATCHER, primero lo crearemos con la constante NO_MATCH que tendra un valor de -1, luego le pasaremos la constante TODOS_LOS_ELEMENTOS y lo relacionaremos con el path “puntuaciones”, el siguiente elemento que agregamos sera UN_ELMENTO y relacionado con el path “puntuaciones/#”, despues tendremos una constante llamada TABLA donde le pasaremos el valor “puntuaciones” y por ultimo crearemos un objeto llamado baseDeDatos de tipo SQLiteDatabase, por ultimo tendremos el metodo onCreate() donde primero crearemos un objeto llamado dbHelper a la cual le pediremos que obtenga el contexto por medio de getContext(), despues por medio de baseDeDatos y dbHelper la daremos la posibilidad de escribir en la misma, la ultima linea devuelve los valores en baseDeDatos siempre que sea distinta de null y la conexion siga abierta, hasta ahora no podemos implementarlo todavia porque para extenderla debemos redefinir las siguientes funciones:

  • getType()
  • query()
  • insert()
  • delete()
  • update()

Dentro de la clase que creamos recien, vamos a agregar el metodo getType():

    @Override
    public String getType(final Uri uri){
        switch (URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                return "vnd.android.cursor.dir/vnd.org.example.puntuacion";
            case UN_ELEMENTO:
                return "vnd.android.cursor.item/vnd.org.example.puntuacion";
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);                    
        }
    }

Este metodo solo obtendra el tipo de URI, para lo cual usara un switch y como referente el URI_MATCHER que definimos antes, en el primer case mirara si coincide con el valor TODOS_LOS_ELEMENTOS, en caso de ser verdadero devolvera el valor informado, el siguiente case chequeara si coincide con UN_ELEMENTO devolvera otro valor, la unica diferencia entre ambos es que el primer case devuelve el directorio y el segundo solo un item de ese directorio, el default solo notificara un error que no coincidio con ninguno de los dos, pasemos al siguiente:

    @Override
    public Cursor query(Uri uri, String[] proyeccion, String seleccion, 
                        String[] argSelec, String orden){
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(TABLA);
        switch (URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                queryBuilder.appendWhere("_id = " + id);
                break;
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return queryBuilder.query(baseDeDatos,proyeccion,seleccion,
                argSelec,null,null,orden);
    }

Este metodo es el encargado de hacer nuestro query, si bien no va a ser muy distinto al original, en este caso vamos a recibir los mismos datos, nuestro primer objeto sera del tipo SQLiteQueryBuilder y lo llamaremos queryBuilder, el cual sera el encargado de construir nuestro query, despues por medio de setTables() le diremos cual es la tabla a utilizar, en este caso tambien tendremos un switch donde chequeara el URI_MATCHER, en el caso de TODOS_LOS_ELEMENTOS no agrega nada, en el caso de UN_ELEMENTO crearemos un objeto llamado id donde le diremos cual debe obtener, luego se lo asignamos por medio de appendWhere() a queryBuilder, y finalmente default al igual que el caso anterior nos devolvera una notificacion si no coinicide con ninguna de las constantes informadas, por ultimo retornaremos el resultado de nuestro query por medio del metodo query en queryBuilder, pasemos al siguiente metodo:

    @Override
    public Uri insert(Uri uri, ContentValues valores){
        long idFila = baseDeDatos.insert(TABLA,null,valores);
        if(idFila>0){
            return ContentUris.withAppendedId(CONTENT_URI,idFila);
        } else {
            throw new SQLException("Error al insertar el registro en " + uri);
        }
    }

Este metodo es mas simple, recibe dos valores: uno va a ser el contenido de tipo uri y otro de valores, nuestra primera linea sera la encargada de ingresar los nuevos valores a la tabla pero almacenara el valor de id de la fila, luego chequearemos si este valor es mayor a cero y lo devolveremos por medio de esta linea de lo contrario devolvera una notificacion de error, observen que el metodo que devuelve los valores tiene el contenido de uri y el valor de id almacenado en idFila, nuestro siguiente metodo es:

    @Override
    public int delete(Uri uri, String seleccion, String[] argSelec){
        switch(URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                if(TextUtils.isEmpty(seleccion)){
                    seleccion="_id=" + id;
                } else {
                    seleccion="_id=" + id + " AND (" + seleccion + ")";
                }
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return baseDeDatos.delete(TABLA,seleccion,argSelec);
    }

Este metodo sera el encargado de eliminar todos los elementos o un elemento en particular, para ello usaremos otra vez el switch como en el caso anterior, con la misma situacion en el case de TODOS_LOS_ELEMENTOS, en el case de UN_ELEMENTO identificaremos devuelta a el id, despues tendremos un condicional que chequea si la seleccion esta vacia y asignara a seleccion el valor de id con la palabra entre comillas, de lo contrario no solamente asignara el id sino a su vez el valor almacenado en seleccion, el default nos devuelve una notificacion en caso de error, por ultimo el return nos devolvera el borrado del o los elementos, veamos el ultimo metodo:

    @Override
    public int update(Uri uri, ContentValues valores, String seleccion, 
                      String[] argSelec){
        switch(URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                if(TextUtils.isEmpty(seleccion)){
                    seleccion="_id=" + id;
                } else {
                    seleccion="_id=" + id + " AND (" + seleccion + ")";
                }
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return baseDeDatos.update(TABLA,valores,seleccion,argSelec);
    }    

En este caso tenemos un metodo exactamente igual en su forma de trabajar a delete() pero la diferencia radica en que redefine y utiliza a update haciendo la modificacion de nuestros valores a diferencia del caso anterior que lo o los elimina, con nuestro ultimo metodo definido veamos como queda el codigo final:

package org.example.puntuacionesprovider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class PuntuacionesProvider extends ContentProvider {

    public static final String AUTORIDAD =
            "org.example.puntuacionesprovider";
    public static final Uri CONTENT_URI = Uri.parse("content://"
            + AUTORIDAD + "/puntuaciones");
    public static final int TODOS_LOS_ELEMENTOS = 1;
    public static final int UN_ELEMENTO = 2;
    private static UriMatcher URI_MATCHER = null;
    static {
        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
        URI_MATCHER.addURI(AUTORIDAD,"puntuaciones",TODOS_LOS_ELEMENTOS);
        URI_MATCHER.addURI(AUTORIDAD,"puntuaciones/#",UN_ELEMENTO);
    }

    public static final String TABLA = "puntuaciones";
    private SQLiteDatabase baseDeDatos;

    @Override
    public boolean onCreate(){
        PuntuacionesSQLiteHelper dbHelper = new
                PuntuacionesSQLiteHelper(getContext());
        baseDeDatos = dbHelper.getWritableDatabase();
        return baseDeDatos != null && baseDeDatos.isOpen();
    }

    @Override
    public String getType(final Uri uri){
        switch (URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                return "vnd.android.cursor.dir/vnd.org.example.puntuacion";
                break;
            case UN_ELEMENTO:
                return "vnd.android.cursor.item/vnd.org.example.puntuacion";
                break;
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
    }

    @Override
    public Cursor query(Uri uri, String[] proyeccion, String seleccion,
                        String[] argSelec, String orden){
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(TABLA);
        switch (URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                queryBuilder.appendWhere("_id = " + id);
                break;
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return queryBuilder.query(baseDeDatos,proyeccion,seleccion,
                argSelec,null,null,orden);
    }

    @Override
    public Uri insert(Uri uri, ContentValues valores){
        long idFila = baseDeDatos.insert(TABLA,null,valores);
        if(idFila>0){
            return ContentUris.withAppendedId(CONTENT_URI,idFila);
        } else {
            throw new SQLException("Error al insertar el registro en " + uri);
        }
    }

    @Override
    public int delete(Uri uri, String seleccion, String[] argSelec){
        switch(URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                if(TextUtils.isEmpty(seleccion)){
                    seleccion="_id=" + id;
                } else {
                    seleccion="_id=" + id + " AND (" + seleccion + ")";
                }
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return baseDeDatos.delete(TABLA,seleccion,argSelec);
    }

    @Override
    public int update(Uri uri, ContentValues valores, String seleccion,
                      String[] argSelec){
        switch(URI_MATCHER.match(uri)){
            case TODOS_LOS_ELEMENTOS:
                break;
            case UN_ELEMENTO:
                String id = uri.getPathSegments().get(1);
                if(TextUtils.isEmpty(seleccion)){
                    seleccion="_id=" + id;
                } else {
                    seleccion="_id=" + id + " AND (" + seleccion + ")";
                }
            default:
                throw new IllegalArgumentException("URI incorrecta" + uri);
        }
        return baseDeDatos.update(TABLA,valores,seleccion,argSelec);
    }    
}

Como pueden ver se agregaron los paquetes necesarios para poder trabajar con ellos, y con estos metodos redefinidos podemos extender a ContentProvider para poder heredar sus propiedades.

En resumen, hoy hemos hecho la clase encargada de implementar el ContentProvider, hemos visto los metodos necesarios que se deben redefinir o sobreescribir para poder implementarla, hemos hecho una clase segura porque ante cualquier eventualidad podremos notificar el error sin que nos cierre la aplicacion, en el proximo post veremos como declararlo en el manifiesto, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios