Fundamentos de Android: Usando el Selector de Contacto
() translation by (you can also view the original English article)
Este tutorial no solamente le mostrará como ejecutar el selector de contacto y obtener resultados, sino también cómo usar esos resultados en Android SDK 2.0 y en versiones superiores.
Comenzar
Este tutorial comenzará simple, pero luego entraremos en algunas de los detalles técnicos de como usar las clases Contacts y ContactsContract, las cuales fueron implementadas en API Level 5. Asegúrese de tener su entorno de desarrollo de Android instalado y configurado correctamente. Tiene la libertad de construir cualquier aplicación que usted tenga, empiece una nueva desde el inicio, o siga usando el código InviteActivity en nuestro proyecto de código abierto.
Después añadiremos la funcionalidad para permitir a un usuario escoger uno de sus contactos existentes y enviares un mensaje enlatado. Vamos a meternos en esto, así que tenga listo todos sus códigos y herramientas. Finalmente, asegúrese de que su dispositivo o emulador tiene configurado algunos contactos (con nombres y correos) dentro de la aplicación Contacts.
Paso 1: Creando su Layout
Hay dos controles de formularios form que son necesarios para que el selector de contactos funciones. Primero, necesitamos un campo de entrada EditText donde se mostrará el correo electrónico resultante. Segundo, necesitamos alguna manera para que el usuario ejecute el selector de contactos. Un control Button funcionará bien para esto.
El siguiente segmento Layout tiene ambos elementos definidos adecuadamente:
1 |
|
2 |
<RelativeLayout
|
3 |
android:layout_height="wrap_content" |
4 |
android:layout_width="match_parent"> |
5 |
<EditText
|
6 |
android:layout_height="wrap_content" |
7 |
android:hint="@string/invite_email_hint" |
8 |
android:id="@+id/invite_email" |
9 |
android:inputType="textEmailAddress" |
10 |
android:layout_width="wrap_content" |
11 |
android:layout_toLeftOf="@+id/do_email_picker" |
12 |
android:layout_alignParentLeft="true"></EditText> |
13 |
<Button
|
14 |
android:layout_width="wrap_content" |
15 |
android:layout_height="wrap_content" |
16 |
android:id="@+id/do_email_picker" |
17 |
android:text="@string/pick_email_label" |
18 |
android:layout_alignParentRight="true" |
19 |
android:onClick="doLaunchContactPicker"></Button> |
20 |
</RelativeLayout>
|
Este layout XML es parte de uno más grande. Así es como luce en el diseñador de layout, completo con los recursos string completados:



Paso 2: Ejecutando el Selector de Contacto
Ahora necesita escribir el código para controlar el Button, el cual presentará el selector de contacto. Una de las características más poderosas de la plataforma Android es que usted puede aprovechar las funcionalidades de otras aplicaciones usando el mecanismo Intent. Un Intent puede ser usado junto con un método startActivityForResult() para ejecutar otra aplicación Android y extraer un resultado. En este caso, usted puede usar un Intent para escoger un contacto desde los datos proporcionados por el proveedor de contenido Contacts.
Aquí esta la implementación del método doLaunchContactPicker():
1 |
|
2 |
import android.provider.ContactsContract.Contacts; |
3 |
import android.provider.ContactsContract.CommonDataKinds.Email; |
4 |
|
5 |
private static final int CONTACT_PICKER_RESULT = 1001; |
6 |
|
7 |
public void doLaunchContactPicker(View view) { |
8 |
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK, |
9 |
Contacts.CONTENT_URI); |
10 |
startActivityForResult(contactPickerIntent, CONTACT_PICKER_RESULT); |
11 |
} |
Nota: Los comandos import son importantes. Asegúrese de que está usando la clase Contacts del ContactsContract y no la clase anterior android.provider.Contacts.
Una vez que es ejecutado, el selector de contactos en su aplicación se verá parecido a algo como esto:



Paso 3: Controlando los Resultados
Ahora está listo para controlar los resultados del selector. Una vez que el usuario abre uno de los contactos en el selector, focus devolverá la llamada para la Activity (la Activity de su aplicación). Usted puede agarrar los resultados del selector de contactos al implementar el método onActivityResult() de su Activiy. Aquí, usted puede revisar que el resultado coincida con su requestCode que el resultado fue bueno. Su implementación del método onActivityResult() debería estar estructurado así:
1 |
|
2 |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
3 |
if (resultCode == RESULT_OK) { |
4 |
switch (requestCode) { |
5 |
case CONTACT_PICKER_RESULT: |
6 |
// handle contact results |
7 |
break; |
8 |
} |
9 |
|
10 |
} else { |
11 |
// gracefully handle failure |
12 |
Log.w(DEBUG_TAG, "Warning: activity result not ok"); |
13 |
} |
14 |
} |
Conseguirá un resultado distinto que RESULT_OK si el usuario cancela la operación o si algo sale mal.
Paso 4: Leyendo los Datos Resultados
El parámetro final para onActivityResult es un Intent llamado "data". Este parámetro contiene el resultado data que estamos buscando. Diferentes Intents devolverán diferentes tipos de resultados. Una opción para inspeccionar los resultados es mostrar todo lo que encontró el paquete Extras además de la data Uri. Aquí está el fragmento de código que mostrará todos los Extras, si alguno existe:
1 |
|
2 |
Bundle extras = data.getExtras(); |
3 |
Set keys = extras.keySet(); |
4 |
Iterator iterate = keys.iterator(); |
5 |
while (iterate.hasNext()) { |
6 |
String key = iterate.next(); |
7 |
Log.v(DEBUG_TAG, key + "[" + extras.get(key) + "]"); |
8 |
} |
9 |
Uri result = data.getData(); |
10 |
Log.v(DEBUG_TAG, "Got a result: " |
11 |
+ result.toString()); |
No estamos muy interesados en el paquete Extras para el selector de contactos porque no contiene la información que necesitamos. Solamente queremos la Uri que nos conducirá a los datos de contactos importantes.
Paso 5: Entender el Resultado
En la función callback: onActivityResult(), estamos facilitando la Uri para el contacto específico que el usuario escoja del selector de contacto. Usar esta Uri directamente nos permitiría conseguir los datos de Contact básicos pero no los detalles. Sin embargo, estamos interesados en determinar la dirección de corre electrónico del contacto. Así que, una forma fácil para resolver esto es con tan solo agarrar el 'contact id' de la Uri, que es el número al final del ruta:
La Uri completa es parecida a:
content://com.android.contacts/contacts/lookup/0r7-2C46324E483C324A3A484634/7
En este caso, el resultado sería simplemente el número 7.
Podemos sacar el identificador del contacto usando el método getLastPathSegment(), como sigue:
1 |
|
2 |
// get the contact id from the Uri |
3 |
String id = result.getLastPathSegment(); |
Paso 6: Consultando la base de datos Contacts para los correos electrónicos
Ahora que tiene el identificador para el contacto elegido, usted tiene toda la información que necesita para consultar directamente el proveedor de contenido Contacts para esa dirección de correo electrónico del contacto. Los proveedores de contenido de Android son un modo poderoso de compartir datos entre las aplicaciones. La interfaz para ellos es parecida a la de la base de datos y muchas son bases de datos respaldadas, usando SQLite, pero no lo necesita.
Una forma como usted puede consultar el proveedor de contenido de contactos para los detalles de contactos adecuados es usando el método por defecto ContentResolver con una de las subclases ContactsContract.CommonDataKinds. Para el correo electrónico, usted puede usar la clase ContactsContract.CommonDataKinds.Email como sigue:
1 |
|
2 |
// query for everything email |
3 |
cursor = getContentResolver().query( |
4 |
Email.CONTENT_URI, null, |
5 |
Email.CONTACT_ID + "=?", |
6 |
new String[]{id}, null); |
Otras subclases útiles como ContactsContract.CommonDataKinds, incluyen Phone, Photo, Website, Nickname, Organization, and StructuredPostal.
Paso 7: Viendo los Resultados de las Consultas
Sin duda, usted podría leer la documentación de la clase para la clase ContactsContract.CommonDataKinds.Email y determinar que tipo de resultados esperar. Sin embargo, esto no siempre es el caso así que vamos a inspeccionar los resultados de esta llamada. Esto es un truco muy práctico si usted está trabajando con un proveedor de contenido que tiene una documentación menos que adecuada, o no está funcionando como se esperaba.
Este fragmento de código le mostrará, por medio de la salida LogCat, que cada columna y valor que es devuelto desde la consulta del proveedor de contenido:
1 |
|
2 |
cursor.moveToFirst(); |
3 |
String columns[] = cursor.getColumnNames(); |
4 |
for (String column : columns) { |
5 |
int index = cursor.getColumnIndex(column); |
6 |
Log.v(DEBUG_TAG, "Column: " + column + " == [" |
7 |
+ cursor.getString(index) + "]"); |
Ahora puede ver que, de hecho, que realmente significan que son el correo electrónico de retorno a través de la columna llamada DATA1, que es enviada por medio del alias Email.DATA. El sistema de Android Contacts es muy flexible, y esto tipo de nombres de columnas genéricas muestra de donde proviene algo de esta flexibilidad. El tipo email, tal como Home o Work, se encuentran en Email.TYPE.
Paso 8: Extrayendo el Email
Tenemos todos los datos que necesitamos para conseguir la dirección de correo electrónico, o las direcciones, del contacto elegido por el usuario. Cuando usamos la base de datos Cursors, tenemos que asegurarnos que, intencionalmente, se están refiriendo a filas de datos en los que estamos interesados, así que empezamos con una llamada el método moveToFirst() y aseguramos que fue un éxito. Para este tutorial, no nos preocuparemos respecto a múltiples direcciones de correos electrónicos. Al contrario, solamente usaremos el primer resultado:
1 |
|
2 |
if (cursor.moveToFirst()) { |
3 |
int emailIdx = cursor.getColumnIndex(Email.DATA); |
4 |
email = cursor.getString(emailIdx); |
5 |
Log.v(DEBUG_TAG, "Got email: " + email); |
6 |
} |
Es importante recordar que un contacto podría tener muchas direcciones. Si usted quiere darle al usuario la opción de escoger entre múltiples direcciones email, entonces podría mostrarle su propio selector de email para que escoja entre estos después que el usuario ha escogido un contacto específico.
Paso 9: Actualizando el Formulario
Después de todo ese trabajo para conseguir la dirección email, no olvide actualizar el formulario. Además, tal vez debería de considerar informar al usuario si el contacto no tenía ninguna dirección email en la lista.
1 |
|
2 |
EditText emailEntry = (EditText)findViewById(R.id.invite_email); |
3 |
emailEntry.setText(email); |
4 |
if (email.length() == 0) { |
5 |
Toast.makeText(this, "No email found for contact.", Toast.LENGTH_LONG).show(); |
6 |
} |
Y ahí está:



Paso 10: Poniéndolo Todo Junto
Nos hemos saltado dos elementos importantes en este tutorial que vale la pena mencionar ahora.
Primero, no incluimos ninguna comprobación de error, hicimos esto por sencillez, pero en la producción de código, esto es una pieza esencial de la solución. Una manera fácil de implementar algunos verificadores sería envolverlo casi todo en un bloque try-catch.
Segundo, necesitamos recordar que los objetos Cursor requieren control dentro de su ciclo de vida Activity. Recuerde siempre liberar los objetos Cursor cuando haya terminado de usarlos.
Aquí está la implementación completa del método onActivityResult() para poner estos puntos en perspectiva:
1 |
|
2 |
@Override |
3 |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
4 |
if (resultCode == RESULT_OK) { |
5 |
switch (requestCode) { |
6 |
case CONTACT_PICKER_RESULT: |
7 |
Cursor cursor = null; |
8 |
String email = ""; |
9 |
try { |
10 |
Uri result = data.getData(); |
11 |
Log.v(DEBUG_TAG, "Got a contact result: " |
12 |
+ result.toString()); |
13 |
|
14 |
// get the contact id from the Uri |
15 |
String id = result.getLastPathSegment(); |
16 |
|
17 |
// query for everything email |
18 |
cursor = getContentResolver().query(Email.CONTENT_URI, |
19 |
null, Email.CONTACT_ID + "=?", new String[] { id }, |
20 |
null); |
21 |
|
22 |
int emailIdx = cursor.getColumnIndex(Email.DATA); |
23 |
|
24 |
// let's just get the first email |
25 |
if (cursor.moveToFirst()) { |
26 |
email = cursor.getString(emailIdx); |
27 |
Log.v(DEBUG_TAG, "Got email: " + email); |
28 |
} else { |
29 |
Log.w(DEBUG_TAG, "No results"); |
30 |
} |
31 |
} catch (Exception e) { |
32 |
Log.e(DEBUG_TAG, "Failed to get email data", e); |
33 |
} finally { |
34 |
if (cursor != null) { |
35 |
cursor.close(); |
36 |
} |
37 |
EditText emailEntry = (EditText) findViewById(R.id.invite_email); |
38 |
emailEntry.setText(email); |
39 |
if (email.length() == 0) { |
40 |
Toast.makeText(this, "No email found for contact.", |
41 |
Toast.LENGTH_LONG).show(); |
42 |
} |
43 |
|
44 |
} |
45 |
|
46 |
break; |
47 |
} |
48 |
|
49 |
} else { |
50 |
Log.w(DEBUG_TAG, "Warning: activity result not ok"); |
51 |
} |
52 |
} |
Ahora tiene todo lo que necesita para completar la aplicación: Sin embargo, recuerde que si está trabajando con datos auténticos, tenga cuidado de no hacer mucho spam a sus amigos. ☺
Conclusión
En este tutorial, aprendió cómo ejecutar un selector de Contacts y a recuperar el resultado elegido. También aprendió cómo inspeccionar los resultados y a extraer las direcciones de correo por el contacto seleccionado usando el proveedor de contenidos contacts. Puede usar este método para extraer todo tipo de información sobre un contacto dado.
Acerca de los Autores.
Desarrolladores de Celulares; Lauren Darcey y Shane Conder son coautores de varios libros sobre el desarrollo en Android: un libro de programación a fondo titulado: Desarrollo de Aplicaciones Inalámbricas de Android y Sams Aprenda usted mismo a Desarrollar Aplicaciones para Android en 24 horas, segunda edición. Cuando no escriben, ellos pasan su tiempo desarrollando programas para celulares en sus empresas y proporcionando servicios de consultoría. Pueden ser localizado a través de correo electrónico: androidwirelessdev+mt@gmail.com o por medio de su blog en androidbook.blogspot.com y en Twitter @androidwireless.