En este video te explicamos en detalle todo el proceso para publicar una Aplicación Android…
Ejemplo de uso de Sync Adapter en un proyecto Android
2.
Ejemplo de uso de Sync Adapter en un proyecto Android
Vamos a ver la implementación de Sync Adapter en una App ejemplo, que nos va a permitir sincronizar datos entre nuestro dispositivo Android y un servidor externo.
A través del desarrollo de este proyecto, explicaremos cómo establecer la sincronización con un gestor de datos de manera automática, en intervalos de tiempos definidos, además de mostrar su funcionamiento de manera manual con la implementación de dos botones para la apertura y cierre de la conexión.
Para ello, utilizaremos un modelo de datos que simula los vehículos disponibles en un concesionario, formados por los campos «_id«, «modelo» y «marca«. Para comprender el funcionamiento de este ejemplo, sólo se mostrará el último registro introducido para visualizar los cambios que se produzcan en la base de datos.
Elementos definidos a nivel de código:
- Clase MainActivity extends Activity para mostrar la información de sincronización con el servidor remoto.
- Clase MiSyncService extends Service para ejecución de tareas en segundo plano.
- Clase MiSyncAdapter extends AbstractThreadedSyncAdapter para la sincronización de las operaciones.
- Clase TareaAsincrona extends AsyncTask<Void, Integer, String> para establecer y definir los parámetros de conexión con el servidor remoto Postgres.
- Librería «postgresql-9.3-1101.jdbc3.jar» para conectarnos al servidor Postgres.
Elementos definidos a nivel de Layout (más significativos):
- Dos componentes de tipo Button (<Button android:id=»@+id/btnArrancar»… y <Button android:id=»@+id/btnParar»)para abrir y cerrar la conexión con el servidor.
- Componente TextView (<TextView android:id=»@+id/txtDatos») para mostrar el último registro almacenado.
- Componente CheckBox (<CheckBox android:id=»@+id/checkSync») para establecer la sincronización con el servidor de manera automática.
Permisos definidos en AndroidManifest.xml
Estos son los permisos que necesita la aplicación para funcionar. Necesitaremos el de acceso a Internet porque obviamente es el nuestro medio de comunicación, los de configuraciones de sincronización porque forman parte del servicio que vamos a utilizar y el de autentificación para que se pueda usar en el acceso a la configuración.
1 2 3 4 |
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> |
Pantalla que muestra la sincronización automática habilitada:
Pantalla que muestra los botones definidos para mostrar el último registro insertado de manera manual:
Código del Proyecto
Vamos a mostrar en detalle las distintas clases y layouts que vamos a utilizar en este proyecto. Como siempre, podrás descargar todo el código al final de este tutorial.
AutenticacionSyncAdapter/com.academiaandroid.autenticacion/src/MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
[...] //Enlazamos los componentes con los recursos definidos a nivel de layout. txtDatos = (TextView)findViewById(R.id.txtDatos); checkSync = (CheckBox)findViewById(R.id.checkSync); btnArrancar = (Button)findViewById(R.id.btnArrancar); btnParar = (Button)findViewById(R.id.btnParar); txtFecha = (TextView)findViewById(R.id.txtFecha); imgRojo = (ImageView)findViewById(R.id.imgRojo); imgAmarillo = (ImageView)findViewById(R.id.imgAmarillo); imgVerde = (ImageView)findViewById(R.id.imgVerde); mAccount = new Account("MiSyncService", getString(R.xml.syncadapter)); [...] [...] //Evento lanzado cuando cambia el estado del checkbox //definido para sincronizar de manera periódica con el servidor remoto. checkSync.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) { if(isChecked) { Bundle params = new Bundle(); params.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false); params.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false); params.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); content = getContentResolver(); ContentResolver.addPeriodicSync(mAccount, AUTHORITY,params, 5); [...] [...] //Evento On Click que abre una conexión con el servidor remoto, //mostrando el último registro introducido en la Base de Datos. public void iniciarConexion(View v) { Toast.makeText(this, "Conexión iniciada con Servidor Remoto", Toast.LENGTH_LONG).show(); TareaAsincrona tarea = new TareaAsincrona(v,this); tarea.execute(); imgRojo.setVisibility(View.INVISIBLE); imgAmarillo.setVisibility(View.INVISIBLE); imgVerde.setVisibility(View.VISIBLE); txtFecha.setTextColor(Color.RED); txtFecha.setText(new Date().toString()); } [...] |
AutenticacionSyncAdapter/com.academiaandroid.autenticacion/src/MiSyncService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
[...] //Clase que hereda de Service para ejecutar aplicaciones de larga duración en segundo plano. public class MiSyncService extends Service{ [...] [...] //El sistema realizada la llamada a este método cuando se crea el servicio por primera vez. @Override public void onCreate() { synchronized (syncAdapterLock) { if (syncAdapter == null) syncAdapter = new MiSyncAdapter(mContext); } } [...] [...] //Clase que hereda de AbstractThreadedSyncAdapter para la sincronización de operaciones. class MiSyncAdapter extends AbstractThreadedSyncAdapter{ [...] [...] //Método que permite la sincronización de esta cuenta. @Override public void onPerformSync(Account account, Bundle extras, String authority,ContentProviderClient provider, SyncResult syncResult) { try{ System.out.println("En onPerformSync"); tareas = new TareaAsincrona(v, main); tareas.execute(); }catch(Exception ex) { System.out.println("Error en onPerformSync: " + ex.getMessage()); } } [...] |
AutenticacionSyncAdapter/com.academiaandroid.autenticacion/src/TareaAsincrona.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
[...] //Clase que hereda de AsyncTask, que nos permite ejecutar un hilo en segundo plano, independiente del hilo de la UI. public class TareaAsincrona extends AsyncTask<Void, Integer, String>{ [...] [...] //Método que se ejecutará en un hilo diferente al de la interfaz de usuario, donde se definen los parámetros para establecer la conexión con el servidor remoto. @Override protected String doInBackground(Void... params) { //Se declaran e inicializan los datos de conexión con el servidor remoto Postgres. String conexion = "jdbc:postgresql://192.168.1.129:5434/Concesionario"; String usuario = "postgres"; String password = "jose110904"; String datos = null; String id = null; String marca = null; String modelo = null; java.sql.Connection conn = null; java.sql.Statement st = null; ResultSet rs = null; //Cargamos el driver del conector JDBC del servidor Postgres. Class.forName("org.postgresql.Driver"); //Establecemos la conexión con el Servidor Postgres indicándole como parámetros la url construida, la Base de Datos a la que vamos a conectarnos, y el usuario y contraseña de acceso al servidor. conn = DriverManager.getConnection(conexion,usuario,password); //Se realiza una consulta Transact-SQL para mostrar todos los vehículos almacenados. String stsql = "Select * from lista_coches"; st = conn.createStatement(); //Se ejecutará la consulta inicializada anteriormente. rs = st.executeQuery(stsql); [...] [...] //Mostramos los registros devueltos por la consulta en el hilo principal de la aplicación. @Override public void onPostExecute(String result) { if(result != null) { Toast.makeText(context, "Mostrando datos del sistema", Toast.LENGTH_LONG).show(); txtDatos = (TextView)context.findViewById(R.id.txtDatos); txtDatos.setTextColor(Color.RED); txtDatos.setText(result); }else { Toast.makeText(context, "La consulta no ha producido resultados", Toast.LENGTH_LONG).show(); txtDatos = (TextView)rootView.findViewById(R.id.txtDatos); txtDatos.setTextColor(Color.RED); txtDatos.setText("Sin resultados"); } } [...] |
AutenticacionSyncAdapter/com.academiaandroid.autenticacion/res/layout/activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
[...] <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:id="@+id/tableRow2" android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:id="@+id/txtDatos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sin Datos" android:textAppearance="?android:attr/textAppearanceLarge" /> </TableRow> <TableRow android:id="@+id/tableRow3" android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:id="@+id/btnArrancar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="iniciarConexion" android:text="Arrancar" /> </TableRow> <TableRow android:id="@+id/tableRow4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="detenerConexion" > <Button android:id="@+id/btnParar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="detenerConexion" android:text="Detener" /> </TableRow> <TableRow android:id="@+id/tableRow5" android:layout_width="wrap_content" android:layout_height="wrap_content" > <CheckBox android:id="@+id/checkSync" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Auto-Sync" /> </TableRow> </TableLayout> [...] |
AutenticacionSyncAdapter/com.academiaandroid.autenticacion/res/xml/syncadapter.xml
1 2 3 4 5 6 7 8 9 10 11 |
[...] <?xml version="1.0" encoding="utf-8"?> <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.academiaandroid.autenticacion.SyncAdapter" android:accountType="com.academiaandroid.autenticacion.SyncAdapter" android:userVisible="false" android:supportsUploading="false" android:allowParallelSyncs="false" android:isAlwaysSyncable="true" /> [...] |
Descarga del código del Proyecto
DownloadEn la siguiente publicación de esta serie explicaremos este mismo proyecto y el funcionamiento de la App en un video.
Esta entrada tiene 6 comentarios
Los comentarios están cerrados.
Estimados, este proyecto me parece que esta desarrollado para Eclipse. Si es asi, estará la versión para Android Studio 1.5.1.
Gracias
Hola Marcelo,
aunque ya todos los proyectos ejemplo se desarrollan en Android Studio, puede haber anteriores que estén en Eclipse.
Iremos haciendo nuevas versiones, pero no es algo que pueda realizar de forma inmediata (también el cambio de versiones de Android puede afectar en algunos casos, al descontinuar alguna clase o introducir nuevos elementos, y ya hemos actualizado en ese sentido algunos proyectos).
Anotamos éste en concreto y te diremos algo.
Saludos
Hola, no permite descargar el código del proyecto.
Hola Alejandro,
como te comentamos en el otro post, y en un email, a nosotros no nos da error. No obstante te lo intentamos enviar a tu email.
Saludos
Acabo de pagar por primiun y no rengo acceso al VIDEO
Hola Carlos, tras hacer login con tu usuario y visitar la página del video ¿has probado a recargarla en tu navegador con F5 (o la opción correspondiente según el navegador que utilices)?
Es algo que indicamos en la página donde haces login: «Si al intentar visualizar un contenido premium te sigue apareciendo restringido, recarga la página en tu navegador con F5 o la opción correspondiente.»
Si te sigue fallando, por favor contacta mejor a través de nuestro correo de soporte: informacion[arroba]academiaandroid.com porque así podremos atenderte mejor.
Gracias