Dev

The Android swissknife

This is a comprehensive list of applications and websites that will make your life much easier when developing Android apps, or at least, my life will be much harder without them. I call it the Android swissknife.

Flat UI Colors: A list of flat colors to use in our apps. Select the format, click the color, and it will be copied to your clipboard.

Android cheat-sheet for Graphic Designers: A big cheatsheet about UI and design related concepts for Android apps. For those like me, who can’t remember the specific size of each icon on each density.

Android Holo Colors: Select the colors, version, controls, and hop! you have a zip file with all the needed drawables and the theme.

Android Asset Studio: Amazing set of assets generators for Android

Parcelabler: Making objects parcellable is boring as hell. With this page, just paste your class code and it will generated a “parcelled” version. Easy peasy.

Android Layout Finder: One of my favorites. Just paste a layout, select the widgets and views and it will automatically generate a findViews method, or an Adapter (even with a ViewHolder). Thanks @EsteveAguilera for sharing it.

Android Layout/Style XML Converter: From layout to style and back.

Jsonschema2Pojo: this is a great one. It generates a pojo from a Json file. You can choose if you want to use Gson or Jackson annotations (and your’ll learn a lot seeing how it does some things).

Roman Nurik’s View Server: This library allows us to use the Hierarchy Viewer from a device apk even if the device is not rooted.

Am I missing something? share in the comments and I’ll update the list.

Update – July 24th

Some other niceties:

DPI calculator for Android: quick DPIs conversion tool. Also available as a Chrome extension.

Gradle, please: a gradle-format dependencies search tool. Useful for the usual suspects.

Android drawable generator: this web generates all the xml stuff for buttons with a lot of settings to play with. It’s a pitty it doesn’t make multiple states.

APK Downloader: this one is supposed to let you download apps from Google Play that are not allowed in your country, but I never managed to make it work as they had a lot of limitations on daily downloads. According to their latest comments, now it works much better, I didn’t tested it lately.

Android Design Tips: another design cheatsheet with a dpi conversion tool

The Android Arsenal: a library and views repository classified by categories.

WSDL2Code: in the last times I had to consume data from SOAP web services. This website will generate pure Android code to access these services from the WSDL specification.Generate, paste and use

En busca de la arquitectura de Android perfecta II: arquitectura general de una app

¡Hola!

Hoy voy a hablar de la arquitectura que suelo seguir en mis apps. Para empezar, unas cuantas normas básicas que siempre sigo:

  • Estoy hablando de apps cliente de una api REST (o similar). Esto no sirve para juegos ni para según que cosas.
  • Todos los datos van a ser persistidos. ¡Si respetas a tu usuario, persiste los datos!
  • La base de datos local no es una base de datos per se, es una caché. La base de datos de verdad está en el servidor, y nosotros sólo tenemos una parte de ella. Tengamos esto siempre en cuenta.
  • Me permito ignorar algunas veces las formas normales en pro de la simplicidad y el rendimiento. Total, sólo soy una caché, la base de datos buena y con datos normalizados está en servidor.
  • Las pantallas de splash en apps de Android son el demonio
  • La guía de estilo es sagrada. Sólo se puede romper para innovar y mejorar. Todavía no he conocido a nadie capaz de hacerlo. Hacerlo diferente no es innovar. Hacerlo como en iPhone no es innovar.
  • Mis reglas son mías y me las salto cuando quiero

Arquitectura general por capas

Durante un par de años trabajé con Code Igniter, un excelente Framework MVC sobre PHP (sí, tengo un pasado como programador de PHP, era joven, necesitaba el dinero). Y yo lo siento, pero por más que miro, no creo que Android sea MVC. Esto es discutir el sexo de los ángeles, hay gente que está de acuerdo conmigo, y gente que no, así que vamos a partir de la idea de que nuestra arquitectura NO se va a basar en MVC.

En cuanto a capas hablamos, yo divido la aplicación en Frontend y Backend, o como les suelo llamar, ui y sdk.

De hecho, en grandes proyectos suelo montar el sdk en un proyecto librería y la ui en un proyecto principal. Esto ayuda mucho a separar estas dos capas y a distribuir el trabajo.

En la capa ui tengo todo aquello encargado de gestionar la interfaz: activities, fragments, views, adapters, etc. Todo ello objetos consumidores de datos. Cae alguna cosilla más que a veces tiene que estar aquí por la idiosincracia de Android aunque no sean ui tal cual, como el objeto Application, Notifications, el Push, etc.

Por otro lado, en la capa de sdk (que tiene la chicha) tengo lo que gestiona los datos: beans, clientes, ContentProviders y tareas (y algunas cosillas más del tipo helpers).

La capa UI

De esta hablaremos otro día a fondo con ejemplos, de momento ahí van algunas generalidades y normas que uso.

Todos los elementos de esta capa los incluyo dentro del paquete ui. Así tendremos ui.activity, ui.fragment, ui.adapter, ui.view, etc.

Todas las clases tienen como sufijo lo que son, por ejemplo MainActivity, ForlayosAdapter, etc.

Cada elemento tiene un conjunto de constantes públicas, finales y estáticas que empiezan por EXTRA con los nombres de los parámetros que pueden ir en el bundle del intent de llamada.

Los Intents entre activities y fragments no se mandan objetos enteros (y mucho menos arrays). Sólo se mandan el id del objeto. Así por ejemplo, si tengo una actividad (o fragment, ahora da igual) ProductListActivity con una lista de productos, al seleccionar uno invoco a la siguiente actividad ProductActivity sólo le paso el id, y esta segunda invoca al content provider para que le retorne el registro y lo lee. Si además los datos pueden cambiar durante su visualización por elementos externos, utilizo un loader para mostrar el detalle.

Los adapters SIEMPRE con ViewHolder.

La capa SDK

Esta capa es la que se encarga de la entrada y salida de datos hacia el servidor y de la persistencia de la misma. Aquí u gráfico con los elementos principales:

android architecture

Repasemos los paquetes que suelo crear y que hay en cada uno:

  • bean: pues aquí van todos los objetos de datos. ¿qué tu le llamas DTO, domain o algo así? pues bién, no me pelearé por eso, pero lo que no hago son distinciones. Cada vez intento que sean los más POJO posibles y no les hago ni getters ni setters, vamos, que son estructuras tontitas con anotaciones para la deserializacíon JSON.
  • client: aquí todos los clientes. Son las representaciones del los servicios web. Por ejemplo, una clase LoginClient invoca al servicio de login, gestiona la respuesta y nos la devuelve procesada. Uso una estructura de IntentService tonto que invoca al servicio web que el client le pasa como parámetros. Ya hablaremos de esto en otro artículo. La gracia del sistema es que haces los client como churros. Aquí se produce la serialización/deserialización a JSON (o lo que toque).
  • model: aquí todo el modelo de datos, en la raíz coloco el contrato de datos, el conjunto de constantes que definen tablas, campos y entidades del content provider. En algunos casos cuando las aplicaciones son muy grandes, separo el contrato de base de datos y el de content provider, pero ojo que entonces el mantenimiento es farragoso y complicado.
  • model.content: los content provider, siguiendo la estructura del artículo anterior con DespicableContentProvider y MinionContentProvider
  • model.cursor: aqui tengo un CursorHelper por entidad. Básicamente se encargan de pasar de registro del cursor a objeto y viceversa
  • model.db: el DatabaseHelper y similares.
  • service: aquí va el IntentService que invocan los clientes, así como cualquier otro servicio que pueda necesitar.
  • task: son procesos atómicos que invocan clientes y ContentProviders. Por ejemplo, la típica tarea de UpdateProductsTask invoca a GetProductsClient, hace un delete sobre el Content Provider de productos y luego un bulk insert. Este proceso tiene una salida indicando si ha ido bien o mal.

El meollo de esto está también en mi librería de acceso a servicios web llamada Rarest. Teneis info en www.rarestandroid.com.

Ale, el próximo día veremos un lindo ejemplo con todo esto.

Looking for the perfect Android architecture I: Despicable Content Providers

I’ve been looking for the best architecture for an Android app. I’m not looking for the best speed or performance, but they should be acceptable. It should be quite Android-compliant and above everything, easy to replicate. My final target is to have a foundation for new projects (pro and personal ones) and be able to say “this is the way I work”. I have a lot of ideas in my mind, but without sharing or discussing them, they are worthless. So, let’s share them, discuss them and let´s improve together.

I’ll start talking about Content Providers (CP). I’m assuming that you know what they are and how they work, and also about SQLite and all the related stuff. If you don’t know about these topics, check out the tutorial from our friend Vogella at  http://www.vogella.com/articles/AndroidSQLite/article.html.

Check section 9.4 of that tutorial. You’ll see the structure of a CP. Basically, four functions, one per operation (query, insert, delete and update) with an structure like this:

I hate the switch statement. I think is ugly and unmaintainable. Also, the example is using only two URLs, but an app with 20 entities will easily become a God class.

My proposal is an structure I call the DespicableContentProvider. Why? because it has MinionContentProviders (I know, don’t use cute names, but I couldn’t resist and the analogy helps a lot to understand it). If you don’t know anything about Despicable and Minions, chech this: http://www.youtube.com/watch?v=jzpOLs1t8Hg

You can check the code both for the Despicable base class and the Minion base class at https://gist.github.com/sergiandreplace/8165986. Free, cute and distributables.

Before start working with them, let’s see some rules I follow when working with CP:

  • The CP works like a web api. Authority is the host name.
  • Every url is an endpoint for an entity.
  • Urls are like content://<authority>/<entity>[/#id].
  • Urls ending with an id are asking for an specific element and are type Item. Other ones are Dir type (for coherence with MIME types)
  • Mime type will be vnd.android.cursor.{dir|item}/vnd.{AUTHORITY}.{ENTITY}. My CP are usually private for the app, so I don’t care too much about MIME types.
  • CP consumers know NOTHING about the database. In fact,  the only one accessing the database is the CP. Even for big projects I use different contracts. One for the database and another one for the CP consumers.
  • When performing an Item request (one with an id in the url) all the filtering parameters are ignored (I’m already asking for only one, why filter?)

Basically, every Minion knows how to perform an Insert, Update, Delete or Query against an entity for an Item or a Dir (not both). Here is an example:

Basically I’ve implemented three things, first getBasePath, that returns the specific url path to the entity, getType function, that returns the name to be used to indentify this entity as MIME type, and the four operations for this specific entity. The main difference with the CRUD opeartions are that you receive the db object via parameter and you don’t need to notify the change as the Despicable will do it.

An Item type is very similar:

The main differences are:

  1. Class name is singular (it’s my way…)
  2. Return path now includes /# as per UriMatcher syntax
  3. On each one of the CRUD operations we ignore the parameters received for filtering and we just query by _id
  4. In this case, I’ve decided you can’t insert an Item specifying an id in the path. This is just an example, and real behaviour will be domain-specific.

Easy peasy, isn’t? So we only need to create one per entity.

Once we have the Minions, let’s work on the Despicable. Check this:

GetAuthority method just returns the name of the authority. It’s used by the parent class to retrieve it on runtime. The method getDb should return a database to work with. The recruitMinions method is responsible to add an instance of each Minion to the collection of the Despicable.

That’s it. Quite cool, isn’t it. At least is tidier and easier to maintain.

Now, our CP implements the  four operations for each entity, and also a bulk insert that just executes the insert in a loop inside a transaction.

And for the same price, a couple of helping functions I usually include in the CP.:

They are very useful in the contract and the CursorHelpers that will be discussed in next entry.

I’d love to receive comments about this and see other points of view and ways of working with CP. And also, any suggestion or improvement will be very welcome.

En busca de la arquitectura Android perfecta I: Despicable Content Providers

Desde hace tiempo vengo buscando cual puede ser la mejor arquitectura de una aplicación Android. Ojo, no tiene por que ser la mejor en cuanto a rendimiento o velocidad, pero tiene que dar un buen rendimiento, ser lo más Android-compliant y sobre todo, fácil de replicar. Mi objetivo no es más que sentar las bases para nuevos proyectos (tanto profesionales como personales) y decir “pues yo trabajo así”. Tengo muchas ideas en la cabeza, pero sin compartirlas y discutirlas, pues no hay manera, así que voy a ir compartiendo algunas de estas ideas, y a ver que sucede.

Hoy empezaré por los ContentProviders. Voy a asumir que ya sabes que es y como funciona un ContentProvider y el acceso a SQLite. Si no lo sabes, mírate el tutorial del amigo Vogella en http://www.vogella.com/articles/AndroidSQLite/article.html. Si os fijas en el punto 9.4 del tutorial, vereis que el estructura el ContentProvider de la siguiente manera por cada una de las operaciones (query, insert, delete y update):

Odio el switch. Me parece la estructura más fea y poco mantenible que existe. Además, en el ejemplo, sólo utiliza dos URLs, pero imaginad una aplicación donde tengo 20 entidades. Vamos, lo que viene siendo una clase Dios.

Mi propuesta para esto es lo que denomino el DespicableContentProvider. ¿Y por qué lo llamo así? Por que tiene MinionContentProvider (lo se, don’t use cute names, pero no pude resistirme, y la analogía se entiendo muy bien). Si no sabes de que va lo de Despicable y Minions, mira esto: http://www.youtube.com/watch?v=jzpOLs1t8Hg

Todo el código base, tanto del DespicableContentProvider como del MinionContentProvider están en https://gist.github.com/sergiandreplace/8165986 y son bonicos, libres y distribuibles.

Antes de todo, establezcamos como uso los ContentProvider y cual es mi approach:

  • El ContentProvider (CP a partir de ahora) lo veo parecido a una api web.
  • Cada url representa una entidad.
  • Las url estan formadas por content://<nombre de la autoridad>/entidad[/#id].
  • Las url acabadas en id estan pidiendo un elemento específico, y las conocemos como tipo Item. Las otras son tipo Dir (por coherencia con los tipos MIME)
  • El tipo mime será vnd.android.cursor.{dir|item}/vnd.{AUTORIDAD}.{ENTIDAD}. Mis CP suelen ser internos no publicados, así que el tipo MIME me da un poco igual.
  • El consumidor del CP no sabe NADA de la base de datos. En realidad, lo monto para que el único que tenga acceso a la bd sea el CP. Incluso los contratos son diferentes, uno para la bd y otro para el CP (a menos que sean algo muy pequeño).
  • Cuando una petición es de tipo Item, es decir, pido uno con un id espécifico, los parametros de filtrado son ignorados (si ya pido uno ¿para que quiero filtrar?)

La idea básica de esta estructura es que cada Minion sabe hacer Insert, Update, Delete y Query de una entidad para Item o para Dir (no ambos). Veamos un ejemplo:

Como veis, he hecho tres cosas, por un lado getBasePath que devuelve la url específica de la entidad, getType, que devuelve el nombre básico para construir el tipo MIME si queremos, y hemos implementado cuatro funciones muy parecidas a las de un ContentProvider normal. Las diferencias son, que por un lado recibo el objeto db para poder lanzar las aplicaciones y no notifico el cambio al acabar.

Uno de tipo Item no tiene mucha diferencia:

Diferencias:

  1. La clase en singular (soy así…)
  2. El path incluye el /# según la sintaxis del UriMatcher
  3. En cada operación, decidimos ignorar los parámetros que recibimos y filtramos por el id de la ruta a piñón.
  4. Decido que el insert de Item no se puede hacer. No hay razón para esto, era por poner un ejemplo. La otra opción sería cambiarlo en el contentValues por el de la url antes del insert. Ahí ya depende de vuestro modelo.

¿A que es facil? Pues creariamos uno de estos por cada entidad Dir o Item  y ale.

Una vez hechos, hay que implementar el Despicable. Que ya vereis que facil:

El método GetAuthority sólo devuelve el nombre de la autoridad que vamos a utilizar. Es usado por la clase padre. El método getDB() debe devolver un objeto Database con el que trabajar. Y el método recruitMinion se encarga de añadir cada uno de los Minions a la colección instanciando las clases que heredan de MinionContentProvider.

Y ya. Mirad que bonico todo.

Ahora nuestro CP ofrece todas las operaciones en cada minion, incluso, de regalo, un bulkInsert que ejecuta un loop de inserts dentro de una transacción.

Ah, suelo añadir estos dos métodos de regalo en el ContentProvider:

Son muy útiles en los contratos y los CursorHelper, que es algo de lo que hablaré el próximo día.

Me encantaría recibir comentarios al respecto y ver como vosotros abordáis el problema. Y cualquier sugerencia, ya sabes, será bienvenida.

Continuous testing on Scala SBT

A nice trick I’ve learned from Ignasi (@ignasi35) one of the BCN Dev Scala Meetup group (http://www.meetup.com/Scala-Developers-Barcelona/)

This is a shortcut to execute the tests while editing the exercises for the Functional Programming course on Coursera.

You can open SBT in your project folder and run the command test. This will compile and run the unit tests defined in the project.

If you run ~test it will run the tests and then it will keep waiting until a file is modified. Once you modify a file, tests will be executed again, and it will keep waiting again, and so on…

Little nice trick 🙂

Uri que te uri

Hola

Me estaba peleando con la camara de Android, y tras “invertir” todo el dia he descubierto una cosilla que a lo mejor os interesa saber.

Estaba llamando a un intent de camara para que me devolviese un fichero, para ello, debemos pasarle un extra con nombre MediaStore.EXTRA_OUTPUT que contenga un objecto Uri apuntando al nombre.

Pues bien, hay varias formas de generar un Uri con métodos de clase:

a) Uri.fromFile(File newUri)

b) Uri.parse(String newUri)

Parece que ambos deberian generar el mismo contenido, pero…. CATACROCKER!

Uri.parse(“/mnt/sdcard/img/photo.jpg”) genera un objeto uri descafeinado. Vamos, le rellena el campo Uri.mPath y pa casa.

Uri.fromFile(new File(“/mnt/sdcard/img/photo.jpg”)) genera un objeto uri con todas sus propiedades y vitaminas.

Pues si al intent de la cámara le pasas el Uri descafeinado, no funciona, si le pasas el segundo (creado con FIle) funciona perfectamente.

Nada, sólo quería compartirlo.

Update 28-agosto-2012

Como dice kix2902 en los comentarios, el Uri.parse funciona con un path del tipo “file://…”.  Lo que no entiendo es por que con una uri incorrecta parsea mal y se queda tan ancho en vez de lanzar una excepción como toca, o al menos no aparece una indicación en la documentación al respecto.

 

Seguimos con Maven. Plantillas.

¡Hola!

Yo sigo erre que erre con Maven. El siguiente paso ha sido crearme una plantilla que contenga la info común en los proyectos Android. Esto es, por supuesto, aplicable a cualquier tipo de proyecto. Los pasos son:

Crear un proyecto nuevo para el POM

En Eclipse creamos un proyecto nuevo de tipo Maven, Maven Project y hacemos clic en siguiente.

Seleccionamos Create a simple project (skip archetype selection) y next.

Introducimos la información del pom. En este caso hablamos de como nos referiremos a nuestra plantilla. Por ejemplo:

  • GroupId: com.sergiandreplace.template
  • ArtifactId: android
  • Version: 0.0.1-SNAPSHOT
  • Packaging: pom <– Aquí está la clave del asunto!!!
  • Name: Android POM template

Por último hacemos clic en Finish y nos creará el proyecto.

Crear el POM base

En este caso, el pom es parecido al que creamos en el último post sobre maven, pero con algunos cambios.

Y con esto tendriamos la plantilla. Básicamente, he extraido los valores que cambian de proyecto en proyecto a variables, y además he creado una sección con valores por defecto.

Para publicarlo en nuestro repo local, tan sólo debemos ejecutar un mvn install y el sólo nos lo añadirá.

Ya tenemos la plantilla lista.

Heredar la plantilla

Ahora en nuestro proyecto Android con maven (recordad el mavenize project) tan sólo necesitamos tener el siguiente pom:

Como veis, aquí le indico, por un lado, de que proyecto hereda la configuración, y por otro lado que valores debe utilizar para las variables. Si  mirais el POM efectivo, vereis que contiene toda la configuración correctamente establecida.

Consideraciones finales

Recordad que si trabajais en equipo, es necesario que todo el mundo tenga las mismas plantillas o la podeis liar muy parda. En ese caso, os recomiendo tener algún repositorio de Maven (p.ej.: Nexus) y tener las plantillas publicadas en el servidor.

El uso de plantillas hace más sencillo el aplicar nuevas configuraciones y opciones a los proyectos existentes, y nos permite configurar los proyectos nuevos de forma más rápida.

Ale, gozadlo.

Ejemplos y comentarios del Barcelona Startup Weekend Bootcamp

El pasado sábado tuve la suerte de poder impartir el Bootcamp del Barcelona Startup Wekeend. Durante esta sesión, vimos una introducción al servicio de GAE para montar un servidor rest y como utilizar la libreria AndroidAnnotations para hacer aplicaciones Android de forma rápida.

Por razones que no acababa de entender, no conseguimos hacer funcionar la libreria AndroidAnnotations como cliente rest, y como sospechaba que era un tema de librerias, prometí mirarlo con calma y postear un proyecto que funcionase.

Después de mucho investigar he encontrado la causa de los problemas y he podido solucionarlos.

Usar Maven con Android

La idea de este artículo es presentar los pasos necesarios para configurar Eclipse para utilizarlo con Maven en proyectos Android. Estos pasos son:

Descargar herramientas

Descargamos Eclipse si no lo tuviesemos (en mi caso utilizo Eclipse Classic 3.7.2) desde http://www.eclipse.org/downloads/.

Configuramos el sdk de Android i el ADT (http://android.com)

Descargamos Maven desde http://maven.apache.org/download.html (para el ejemplo usamos 3.0.4)

Asumimos que instalamos las herramientas en D:eclipse, D:android-sdk-windows y en D:maven si tu ruta es diferente, cambialo donde toque.

Instalar plugin de Eclipse para Maven (m2Eclipse)

Desde http://www.eclipse.org/m2e/download/ podemos ver las diferentes rutas de descarga.

En nuestro caso, en Eclipse, vamos a Help, Install New Software… e introducimos http://download.eclipse.org/technology/m2e/releases como url.

Configurar el plugin de Maven

En mi caso configuro siempre lo siguiente:

En la venta de preferencias (Window, Preferences) seleccionamos MavenInstallations. Allí podemos añadir el ejecutable de Maven. Así nos aseguramos que el plugin y la linea de comandos utilizan la misma versión.

Instalar el conector de Android para Maven

Ahora hay que decirle al plugin que “entienda” los proyectos de Android. Para eso tenemos que instalar el conector de Android. Dentro de la pantalla de preferencias, en MavenDiscovery, hacemos clic en Open Catalog. Se nos abrirá el listado de conectores.

Buscamos ‘Maven Integration for Android Development Tools’ (escribe Android y acabarás antes) y lo instalamos.

Ya estamos listos para trabajar con Maven para Android.

Configurar un proyecto para usar Maven

Nunca he conseguido que creando un proyecto nuevo de Maven directamente funcione. Lo que hago es crear un proyecto normal, y luego, podemos hacer clic con el botón derecho sobre la raiz del proyecto, y seleccionar Configure, Convert to Maven Project.

Así se nos transformará en un proyecto de Maven, pero nos toca configurar el POM. Básicamente, utilizo la siguiente plantilla:

Y aquí algunos de los valores a configurar:

  • GROUP_ID_DEL_PROYECTO: la ruta canónica del paquete (p.ej.: com.sergiandreplace)
  • NOMBRE_DEL_PROYECTO: el identificador del paquete que completa la ruta canónica.
  • VERSION_DE_ANDROID: la versión de Android que utilizamos en la app. Ojo que no valen todas, sólo aquellas que estén en el repositorio. Podemos consultar la lista aquí: http://mvnrepository.com/artifact/com.google.android/android
  • NOMBRE_FINAL_APK: pues eso, el nombre que tendrá el fichero final cuando compilemos.
  • VERSION_DE_API: versión de api utilizada para compilar en formato numérico. P.ej: 7 para 2.1

Si ahora ejecutamos desde la linea de comandos en la carpeta del proyecto

Se nos instalaran las dependencias necesarias
Ahora si ejecutamos

Se nos compilará e instalará en los moviles disponibles desde adt.

También podemos hacer un compilado/ejecución de toda la vida en Eclipse.

Quedan cosas por configurar (donde hacer deploy, certificados, etc) pero esto ya depende de cada proyecto, aquí sólo he mostrado lo mínimo para empezar.

Charla sobre Mercurial por Jordi Gerona

Ayer asistí a una charla sobre Mercurial que impartió Jordi Gerona (de Eventuo) en Barcelona Activa a de la mano de SeedRocket.

Aunque estaba orientado a usuarios de SVN (Subversion) con ganas de conocer Hg (Mercurial) y yo no soy un experto en SVN (vamos, más bien novatillo), el buen hacer de Jordi ayudó bastante a seguir los conceptos explicados (sobre todo algunos que son complejos en Hg).

Y francamente, me vendió el producto. He estado haciendo algunas pruebas con BitBucket, y me está gustando mucho. Funciona bien, es rápido y sobre todo gratis (y no me obliga a que mis proyectos sean open source).

La idea básica de Mercurial es que no tenemos una estructura cliente/servidor como en SVN, al contrario, se trata de una arquitectura distribuida (de ahí su nombre DCVS, Distributed Control Version System), donde nos sincronizamos contra otros repositorios. Por comodidad, se tiene uno centralizado pasivo, pero que no manda sobre los demás y en vez de C/S tenemos repositorio local y remoto.

Así pues, tenemos nuestra working folder al igual que en SVN, pero la sincronizamos contra nuestro repositorio local (sito en la misma working folder). Cuando nuestros cambios estan listos para ser distribuidos, descargamos los últimos cambios del repositorio remoto, sincronizamos el head local y el head remoto en nuestro repositorio local, y mandamos estos cambios al remoto.

Un poco complicado de explicar en tres líneas, pero por suerte, Jordi ha compartido la presentación en Slide Share, y Fernando Cejas (de Android10) tuvo a bien de grabarlo en video (la calidad de imagen no es lo más mejor, que lo hizo con el teléfono, pero el audio es lo importante).

Aqui la presentación: http://www.slideshare.net/giro9/mercurial

Aquí el video: http://www.slideshare.net/giro9/mercurial

P.D.: el preguntón del principio que no para de interrumpir soy yo. Sorry Jordi, es que cuando algo me interesa, me pongo muy pesado.