Leer información de un ContentProvider

Veamos un ejemplo que permite leer el registro de llamadas del teléfono. Crea una nueva aplicación con los siguientes datos:

Application Name: ContentCallLog

Package Name: org.example.contentcalllog

Minimun Requiered SDK: API 7: Android 2.1 (Eclair)

Reemplaza el contenido del fichero res/layout/activity_main.xml por:

<LinearLayout

   xmlns:android="http://schemas.android.com/apk/res/android"

   android:orientation="vertical"

   android:layout_width="fill_parent"

   android:layout_height="fill_parent">

   <TextView 

      android:id="@+id/salida"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:text="@string/hello"/>

</LinearLayout>

De esta forma podremos identificar el TextView desde el programa y utilizarlo para mostrar la salida.

Añade al final del fichero AndroidManifest.xml las líneas:

<uses-permission

      android:name="android.permission.READ_CALL_LOG">

</uses-permission>

Al solicitar el permiso READ_CALL_LOG podremos acceder al registro de llamadas. Añade al final del método onCreate de la actividad principal el siguiente código:

 ...

    String[] TIPO_LLAMADA = {"","entrante","saliente","perdida"};

    TextView salida = (TextView) findViewById(R.id.salida);

    Uri llamadas = Uri.parse("content://call_log/calls");

    Cursor c = managedQuery(llamadas, null, null, null, null);

    while (c.moveToNext()) {

           salida.append("\n"

                 + DateFormat.format("dd/MM/yy k:mm (",

                                      c.getLong(c.getColumnIndex(Calls.DATE)))

                  + c.getString(c.getColumnIndex(Calls.DURATION)) + ") "

                 + c.getString(c.getColumnIndex(Calls.NUMBER)) + ", "

                 + TIPO_LLAMADA[Integer.parseInt(c.getString(c

                                                               .getColumnIndex(Calls.TYPE)))]);

           }   

En primer lugar se define un array de strings, de forma que TIPO_LLAMADA[1] corresponda a“entrante”, TIPO_LLAMADA[2] corresponda a “saliente”, etc. Luego se crea el objeto salida que es asignado al TextView correspondiente del Layout.

Ahora comienza lo interesante, creamos la URI, llamadas asociada acontent://call_log/calls. Para realizar la consulta creamos el Cursor, c. Se trata de la misma clase que hemos utilizado para hacer una consulta en una base de datos, pero ahora la información será suministrada por un ContentProvider por medio del método manageQuery(). Este método permite varios parámetros para indicar exactamente los elementos que nos interesan, de forma similar a como se hace en una base de datos. Estos parámetros serán estudiados más adelante. Al no indicar ninguno se devolverán todas las llamadas registradas.

No tenemos más que desplazarnos por todos los elementos del cursor (c.moveToNext()) e ir añadiendo la salida (salida.append()) la información correspondiente a cada registro. En concreto fecha, duración, número de teléfono y tipo de llamada. Una vez que el cursor se encuentra situado en una fila determinada, podemos obtener la información de una columna utilizando los métodosgetString(), getInt(), getLong() y getFloat() dependiendo del tipo de dato almacenado. Estos métodos necesitan como parámetros el índice de columna. Para averiguar el índice de cada columna utilizaremos el método getColumnIndex() indicando el nombre de la columna. En nuestro caso estos nombres son “date”, “duration”, “number” y “type”. En el ejemplo, en lugar de utilizar estos nombres se han utilizado cuatro constantes definidas con estos valores.

Especial mención tiene la columna “date” que nos devuelve un entero largo que representa un instante concreto de una fecha. Para mostrarla en el formato deseado hemos utilizado el método estático format() de la clase DateFormat.

El resultado de ejecutar este programa se muestra a continuación:

 

Veamos con más detalle el método managedQuery():

 

Cursor managedQuery(Uri uri, String[] proyeccion, String seleccion, String[] argsSelecc, String orden)

 

Donde los parámetros corresponden a:

 

uri                               URI correspondiente al ContentProvider a consultar.

proyeccion       Lista de columnas que queremos que nos devuelva.

seleccion        Clausula SQL correspondiente a WHERE.

argsSelecc       Lista de argumentos utilizados en el parámetro seleccion.

orden                           Clausula SQL correspondiente a ORDER BY.

Para ilustrar el uso de estos parámetros reemplaza en el ejemplo anterior:

Cursor c = managedQuery(llamadas, null, null, null, null);

por,

 

String[] proyeccion = new String[] {

       Calls.DATE, Calls.DURATION, Calls.NUMBER, Calls.TYPE };

String[] argsSelecc = new String[] {"1"};     

Cursor c = managedQuery(

       llamadas,      // Uri del ContentProvider 

       proyeccion,    // Columnas que nos interesan

       "type = ?",    // consulta WHERE

       argsSelecc,    // parámetros de la consulta anterior

       "date DESC");  // Ordenado por fecha, orden ascenciente

 

De esta forma nos devolverán solo las columnas indicadas en proyeccion. Esto supone un ahorro de memoria en caso de que existan muchas columnas. En el siguiente parámetro se indica las filas que nos interesan por medio de una consulta de tipo WHERE. En caso de encontrar algún carácter ? este es sustituido por el primer string del parámetro argSelecc. En caso de haber más caracteres ? se irían sustituyendo siguiendo el mismos orden. Cuando se sustituyen los interrogantes cada elemento de argSelecc es introducido entre comillas. Por lo tanto, en el ejemplo la consulta WHERE resultante es “WHERE type = ’1’”. Esta consulta implica que solo se mostrarán las llamadas entrantes. El último parámetro sería equivalente a indicar en SQL “SORTED BY date DESC” es decir el resultado estará ordenado por fecha en orden ascendiente.