Parte 3: Añadir funciones de sincronización a un servidor centralizado
Este blog de varias partes ayudará al lector a construir una aplicación móvil de extremo a extremo utilizando las características líderes en la industria de Couchbase Lite.
Una aplicación de última generación, de extremo a extremo, escalable y apta para la producción debe incluir las siguientes características:
-
- Una base de datos integrada para almacenar datos localmente en el dispositivo y reducir los desplazamientos por la red a una base de datos centralizada para cada actividad. Esto contribuye en gran medida a mejorar la experiencia del usuario.
- Realiza búsquedas de texto completo en el dispositivo.
- Sincronización con dispositivos móviles pares y un servidor centralizado.
Esta serie de entradas de blog se divide en cuatro partes:
-
- Parte 1 muestra el proceso de creación de una aplicación móvil que aprovecha CB Lite y la utiliza como base de datos integrada para almacenar datos.
- Parte 2 muestra cómo ejecutar la búsqueda de texto completo (FTS) en el dispositivo.
- La Parte 3 introduce la sincronización con un servidor Couchbase centralizado desde dispositivos edge.
- La Parte 4 demostrará la sincronización peer-to-peer entre dispositivos.
Estamos construyendo esta aplicación sobre Servidor Couchbase y con Couchbase Móvil utilizado en el dispositivo y para la gestión de la sincronización.
Couchbase es una galardonada base de datos distribuida NoSQL en la nube. Ofrece una versatilidad, un rendimiento, una escalabilidad y un valor financiero inigualables en implementaciones en la nube, locales, híbridas, en la nube distribuida y de computación perimetral.
En Couchbase Móvil La cartera incluye:
-
- Base de datos integrada para dispositivos periféricos.
- Una pasarela de sincronización de alto rendimiento que ofrece funciones de sincronización entre pares y con servidor centralizado.
- Centros de datos Edge basados en Couchbase Server que pueden desplegarse en la nube, on-prem o localmente.
Añadir la función Sync
El código de este tutorial está disponible en mi sofábasamóvil Repositorio GitHub. Estamos trabajando con el RateIt que forma parte del archivo Rateit.zip, extraiga sus archivos a una carpeta local.
También puedes seguir las instrucciones de esta serie de blogs para crear la aplicación desde cero.
Las funciones de la aplicación se dividen en tres partes:
-
- envío de solicitudes
- recibir peticiones de otros
- ver la solicitud que ha enviado
Enviar solicitudes de valoración
La aplicación que crearemos en este tutorial permitirá a los usuarios enviar una solicitud de clasificación temática a una persona y recibir sus respuestas.
A ENVIAR A indica el número de teléfono de la persona a la que desea enviar la solicitud.
En Mensaje indica qué quieres que hagan con él. En este caso, como se trata de una solicitud de valoración, tengo un mensaje predefinido de: "Calificar 1-5" - indicando que tienen que proporcionar una calificación cuando envíen la solicitud de vuelta.
En Asunto indica cualquier tema sobre el que desee una calificación, por ejemplo, puede ser simplemente una palabra o frase como:
-
- Actor: Chris Hemsworth
- Libro: Orgullo y prejuicio
- www.google.com
No hay ninguna validación de entrada estricta en los campos, pero eso es algo que se haría para una aplicación móvil de nivel de producción.
Al hacer clic en ENVIARse envía una solicitud a la persona destinataria.
Requisitos previos del software
En esta parte del blog, requerimos que se instale el siguiente software en un ordenador de sobremesa o servidor al que accederá su aplicación móvil.
Servidor Couchbase - Instale una versión en su portátil o servidor local utilizando este enlace de descarga gratuita. Una vez instalado correctamente, debería poder acceder a la consola de Couchbase desde su navegador en https://localhost:8091.

Servidor Sync Gateway - Esto puede ser en la misma máquina de desarrollo que Couchbase Server. Descargue Sync Gateway aquí y revise el documentación.

Siga todos los Comience aquí pasos de la documentación, resaltados aquí en verde.

Para empezar, haz lo siguiente:
-
- Inicie Sync Gateway en su ordenador portátil.
- Complete todos los pasos de la sección de verificación.
- Dé al usuario acceso a todos los canales con esta sentencia curl:
|
1 2 3 4 |
curl --location --request PUT 'https://127.0.0.1:4985/rateit/_user/sgwuser1' \ --header 'Authorization: Basic c3luY19nYXRld2F5OnBhc3N3b3Jk' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "sgwuser1", "roles": ["stdrole"] ,"admin_channels": ["*"]}' |
Presentamos la aplicación móvil RateIt
Como se muestra en las entradas anteriores, la página principal de la aplicación tiene tres botones:
-
- HAGA CLIC PARA ENVIAR UNA SOLICITUD DE VALORACIÓN
- SOLICITUDES DE CALIFICACIÓN RECIBIDAS
- SOLICITUDES DE CALIFICACIÓN RECIBIDAS
Añadiremos componentes de interfaz de usuario que permitan activar y desactivar la sincronización, así como una entrada de texto para que los usuarios se identifiquen.
Los archivos de código que manipularemos son mainactivity.java y activity_main.xml.
La sincronización desde el dispositivo móvil al servidor centralizado es para aplicaciones que necesitan actualizar constantemente un servidor centralizado con cualquier cambio de los dispositivos de mano. Esta sincronización aplicará esos cambios a otros dispositivos si también comparten la misma aplicación y conexión a la base de datos centralizada.
Revisión del código de sincronización del servidor
Añada el siguiente código a activity_main.xml para incorporar la sincronizar interruptor. Es un interruptor de encendido/apagado que permite al usuario decidir cuándo activar la sincronización.
|
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 |
<Switch android:id="@+id/switch1" android:layout_width="158dp" android:layout_height="38dp" android:layout_marginStart="2dp" android:layout_marginTop="8dp" android:layout_marginEnd="2dp" android:layout_marginBottom="8dp" android:background="#F44336" android:backgroundTint="#F44336" android:checked="false" android:switchMinWidth="50dp" android:switchTextAppearance="@style/TextAppearance.AppCompat.Body2" android:text="SYNC ON/OFF" android:textColor="@color/black" android:textOff="OFF" android:textOn="ON" android:textSize="16sp" android:textStyle="bold" android:visibility="visible" app:layout_constraintBottom_toTopOf="@+id/send" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> |
El siguiente fragmento XML toma el nombre de usuario como entrada del usuario y tiene una etiqueta asociada para facilitar su uso.
|
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 |
<TextView android:id="@+id/textView5" android:layout_width="51dp" android:layout_height="35dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="#2196F3" android:gravity="center" android:text="USER" android:textStyle="bold" app:layout_constraintStart_toEndOf="@+id/switch1" app:layout_constraintTop_toBottomOf="@+id/textView" /> <EditText android:id="@+id/username" android:layout_width="154dp" android:layout_height="35dp" android:layout_marginStart="67dp" android:layout_marginTop="8dp" android:background="@color/white" android:backgroundTint="@color/white" android:ems="10" android:inputType="textPersonName" android:text="Name" app:layout_constraintStart_toStartOf="@+id/textView5" app:layout_constraintTop_toBottomOf="@+id/textView" /> |
La página de inicio de la aplicación tendrá ahora este aspecto, fíjese en los nuevos componentes de la fila superior:

Ahora actualizaremos Mainactivity.java en el Java → com.example.rateit con estos cambios:
-
- Añadir código que compruebe si el sincronizar debe estar activado.
- También añadir código para obtener la entrada de la usuario campo de entrada
|
1 2 3 |
Switch toggleBtn = (Switch) findViewById(R.id.switch1); EditText userid = (EditText) findViewById(R.id.username); String username = userid.getText().toString(); |
Añade un receptor para la función sincronizar que hace lo siguiente:
-
-
- Cuando el botón de conmutación se cambia de EN a OFF, o viceversa, escuchará estos cambios y actuará en consecuencia.
- Cuando se gira el botón OFFla replicación se detendrá.
- Cuando el botón EN se iniciará la replicación.
- Cuando se activa la replicación, instanciamos la configuración del replicador con la base de datos local y proporcionamos detalles de la base de datos centralizada para indicar la fuente y el destino de las réplicas push/pull.
-
|
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 |
toggleBtn.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){ @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Replicator replicator = null; if(isChecked) { DatabaseConfiguration config = new DatabaseConfiguration(); File dbFile = new File(context.getFilesDir() , "rateitdb"); config.setDirectory(context.getFilesDir().getAbsolutePath()); Database database = null; try { database = new Database("rateitdb", config); } catch (CouchbaseLiteException e) { e.printStackTrace(); } URI url = null; try { url = new URI(String.format("%s/%s", "ws://10.0.2.2:4984", "rateit")); } catch (URISyntaxException e) { e.printStackTrace(); } Query query = null; CouchbaseLite.init(context); ReplicatorConfiguration replconfig = new ReplicatorConfiguration(database, new URLEndpoint(url)); replconfig.setType(ReplicatorType.PUSH_AND_PULL); replconfig.setContinuous(true); replconfig.setAuthenticator(new BasicAuthenticator("sgwuser1", "password".toCharArray())); replicator = new Replicator(replconfig); setRepEventMonitor(replicator); replicator.start(); Log.i(LogDomain.REPLICATOR.name(),"Enabled replication"); } else { replicator.stop(); Log.i(LogDomain.REPLICATOR.name(),"Disabled replication"); } } }); CouchbaseLite.init(context); } |
Configure el monitor de eventos para los eventos de replicación:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public void setRepEventMonitor(Replicator replicator) { ListenerToken token = replicator.addDocumentReplicationListener(replication -> { for (ReplicatedDocument document : replication.getDocuments()) { Log.i(TAG, "Doc ID: " + document.getID()); CouchbaseLiteException err = document.getError(); if (err != null) { //There was an error Log.e(TAG, "Error replicating document: ", err); return; } } }); } |
En Mainactivity.java también eliminamos muchos valores codificados de los registros de solicitudes, para que podamos mostrar los registros tal y como los verían distintos usuarios.
En el SENDDATA observe cómo los valores codificados se sustituyen por los campos de entrada correspondientes:
|
1 2 3 4 5 6 7 8 |
MutableDocument mutableDoc = new MutableDocument(); mutableDoc.setString("type", "send"); mutableDoc.setString("sendto", String.valueOf(sendto)); mutableDoc.setString("from", username); mutableDoc.setString("to", sendto); mutableDoc.setString("URL", String.valueOf(URLlink)); mutableDoc.setString("rating", String.valueOf(rating)); mutableDoc.setDate("createdAt", new Date()); |
En el RECEIVEDATA eliminamos la escritura adicional que antes emulaba la obtención de una solicitud de valoración. Ahora que hemos añadido la función USUARIO campo de entrada que nos permite obtener la calificación / solicitudes de vuelta para el usuario específico.
|
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 |
SearchView search = (SearchView) findViewById(R.id.searchView); Expression searchExp = FullTextExpression.index("descFTSIndex").match(String.valueOf(search.getQuery())) ; Query query = null; if (search.getQuery().toString().trim().isEmpty()) { query = (Query) QueryBuilder.select(SelectResult.all()).from(DataSource.database(database)) .where(Expression.property("to").equalTo(Expression.string(username)) .and(Expression.property("type").equalTo(Expression.string("send")))); } else { query = (Query) QueryBuilder.select(SelectResult.all()).from(DataSource.database(database)) .where(Expression.property("to").equalTo(Expression.string(username)) .and(Expression.property("type").equalTo(Expression.string("send"))) .and(searchExp)); } int numrows = query.execute().allResults().size(); Toast.makeText(getApplicationContext(), "num rows:::"+ numrows , Toast.LENGTH_LONG).show(); try { query.execute().allResults().forEach(result -> { Dictionary thisDocsProps = result.getDictionary(0); String from = thisDocsProps.getString("from").trim(); String to = thisDocsProps.getString("to").trim(); String sendto = thisDocsProps.getString("sendto").trim(); String URL = thisDocsProps.getString("URL").trim(); String rating = thisDocsProps.getString("rating").trim(); float ratingstars = thisDocsProps.getFloat("ratingstars"); int stars = (int) ratingstars; rating = String.valueOf(thisDocsProps.getFloat("ratingstars")); userArray.add(new User(username,from, sendto, URL, rating,ratingstars)); }); } catch (CouchbaseLiteException e) { e.printStackTrace(); } |
En el INCOMINGRATINGS recorte el código para obtener solicitudes basadas en nombre de usuario:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Query query = (Query) QueryBuilder.select(SelectResult.all()).from(DataSource.database(database)) .where(Expression.property("from").equalTo(Expression.string(username)) .and(Expression.property("type").equalTo(Expression.string("rated")))); int numrows = query.execute().allResults().size(); Toast.makeText(getApplicationContext(), "num rows:::"+ numrows , Toast.LENGTH_LONG).show(); try { query.execute().allResults().forEach(result -> { Dictionary thisDocsProps = result.getDictionary(0); String sendto = thisDocsProps.getString("sendto").trim(); String URL = thisDocsProps.getString("URL").trim(); String rating = thisDocsProps.getString("rating").trim(); float ratingstars = thisDocsProps.getFloat("ratingstars"); int stars = (int) ratingstars; rating = String.valueOf(thisDocsProps.getFloat("ratingstars")); RatedArray.add(new Rated(sendto, URL, rating)); }); } catch (CouchbaseLiteException e) { e.printStackTrace(); } |
Se introducen algunas actualizaciones en el UserCustomAdapter.java y RatedCustomerAdapter.java. Para esta iteración, vamos a eliminar un montón de hardcoded DESDE y A porque queremos mostrar la aplicación para dos usuarios diferentes. Esto ayuda a mostrar cómo funciona la sincronización bidireccional entre la aplicación y el servidor.
Se han introducido cambios similares para eliminar los nombres codificados de forma rígida. nombre de usuario y solicitar desde la página principal de la aplicación.
Compilación del código de la aplicación móvil
Una vez actualizado todo el código, haga clic en Construir → Reconstruir proyectoentonces Construir → Ejecutar cuando se haya completado la reconstrucción.
Se te pedirá que elijas el emulador la primera vez que ejecutes la aplicación. He creado el dispositivo NEXUS 5X API 25 y lo he elegido cuando se me ha preguntado.
Una vez finalizada la ejecución, la página principal tendrá el siguiente aspecto:

Ahora ha desplegado con éxito el código en el emulador de su elección.
Una prueba rápida
Vamos a crear una solicitud de calificación siguiendo estos pasos:
- Gire el SYNC encender.
- Introduzca los detalles de la solicitud de clasificación (usuario de destino, mensaje, asunto).
- Haga clic en HAGA CLIC PARA ENVIAR UNA SOLICITUD DE VALORACIÓN.
- Ve a la instancia de Couchbase Server. En mi caso, es la consola web de mi instancia local. Navega a Cubos y Documentos y debería ver la solicitud de clasificación creada en el servidor.
- Ahora introduce el nombre de usuario AlPacino y haga clic en SOLICITUDES DE CALIFICACIÓN RECIBIDAS-debería ver la solicitud de calificación en el RECIBIDO sección lista para ser valorada. Valore esta solicitud.
- Cuando compruebe la consola verá dos documentos JSON como se muestra a continuación.



Observe los dos registros en la consola.

Ahora vamos a hacer un cambio en la solicitud clasificada por AlPacino y cambiar el número de estrellas a 2 y ver si los cambios llegan al dispositivo.

Ejecuta la aplicación y abre SOLICITUDES CLASIFICADAS ENTRANTES (parte inferior de la pantalla) para TomCruise y verá el cambio a 2 estrellas.

Próximos pasos
Esta es la parte 3 de la serie de blogs Construyendo una aplicación móvil con Couchbase. Este post muestra cómo habilitar la sincronización dispositivo-servidor.
En la siguiente parte de la serie te mostramos cómo activar la sincronización de dispositivos peer-to-peer.
Continúe aprendiendo siguiendo estos recursos:
