Carlos Robles frikiblog

13/08/2013
by carlosrobles
0 comments

return fully qualified ViewModels – Mejorar el rendimiento, o forzar una vista concreta.

En Zend Framework 2, por lo general para cargar una vista, en nuestro controlador hacemos una de estas dos cosas

public function unaAction()
{
return array( /*valores a pasar a la vista*/ );
}
//o un poco mas explícito

public function otraAction()
{
return new ViewModel(array(/*valores a pasar a la vista*/));
}

¿Qué implica esto?

ZF2 utiliza la llamada “PhpRenderer-Strategy”, que va a hacer una serie de comprobaciones, sobre el valor devuelvto por un controlador-accion.

  1. Si es solo un array, el framework crea un ViewModel.
  2. Después se busca el template asignado. Si no hay ninguno explícito, el framework busca el que corresponda, comprobando el módulo actual, el controlador actual, y la acción actual. Basado en eso se localiza un archivo con la vista correspondiente.
  3. Después de esto, el renderizado puede empezar.

Esto está bien, pero tiene dos limitaciones:

  1. El rendimiento no es el mejor. El framework esta haciendo muchas comprobaciones para algo que no cambia en runtime y nosotros sabíamos por adelantado.
  2. El template cargado depende del modulo/controlador/acción solicitado, pero puede que para el mismo el modulo/controlador/acción nos interese una diferente colección de plantillas,  por ejemplo si el usuario solicita un listado segun unos criterios, puede que tengamos un template para el listado, y queramos tener otro archivo para cuando no hay resultados, y queremos hacerlo sin introducir lógica en la vista y mezclar cosas distintas, y no tener que hacer redirecciones o trucos de magia.

¿Alternativa?

Fácil, tanto para la segunda situacion, como en general si queremos mejorar el rendimiento, podemos decirle al ViewModel que template nos interesa que carge.

public function unaAction() {
$viewModel = new  ViewModel();

$viewModel->setTemplate('MODULO/CONTROLADOR/ACCION');

/*Yo  uilizo el modulo y controlador real, pero el nombre de la acción puede o no corresponder a una acción que exista de verdad, con tal de que el template correspondiente si que exista.  Por ejemplo:

if (count($elementos))
$viewModel->setTemplate('elementos/buscar/index');

else
$viewModel->setTemplate('elementos/buscar/sinresultados');
 

*/

return $viewModel->setVariables(array(/*valores a pasar a la vista*/));

}

Y eso es todo.

Si lo queremos hacer por temas de rendimiento, por su puesto que es mucho mas tedioso que la forma habitual, pero está bien considerarlo en aplicaciones con mucho uso a las que realmente necesitemos sacar el máximo.

06/08/2013
by carlosrobles
0 comments

Zend Framework 2.0 Router

Dejo un enlace con una buena recopilación de las posibilidades del router de ZF2. Sirve para entender lo simple y lo no tan simple, a siempre que se tenga un  poco de base en ZF2.  Algunas cosas quedan suficientemente claras para poder empezar a usarlas sin más, otras necesitan un poco más de profundización. En todos los casos es una buena  referencia:

http://evan.pro/zf2-router-talk.html

05/08/2013
by carlosrobles
0 comments

Doctrine 2 ReflectionException – class does not exist

Cuando estamos trabajando con clases con anotaciones en doctrine 2, dentro de Zend Framework 2, si una clase tiene un campo que hace referencia a otra entidad (una relación manyToOne, ManyToMany, o lo que sea) y esa entidad, tiene otro campo que hace referencia a una tercera entidad, lo más normal es que tengamos problemas.

Esto es porque al parecer, los namespaces no viajan bien por todas las funciones que utiliza el ORM para cargar las clases necesarias y crear los objetos, si no lo especificamos correctamente. Si hemos creado nuestras clases a través de ingeniería inversa, puede que doctrine no nos haya creado los parámetros de la mejor forma posible si estamos trabajando con namespaces propios (que es lo más habitual), y por tanto hará falta un poco de retoque.

Por ejemplo, si tenemos una tabla localidad, con una columna provincia, que hace es clave externa, doctrine nos crearía una entidad como la que pongo a continuación. Para englobar todas entidades utilizo DBAL\Entity

<?php
 namespace DBAL\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * GeoLocalidad
 *
 * @ORM\Table(name="geo_localidad")
 * @ORM\Entity
 */
class GeoLocalidad
{
 /**
 * @var string
 *
 * @ORM\Column(name="nombre", type="string", length=45, nullable=true)
 */
 private $nombre;

 /**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
 private $id;

 /**
 * @var \GeoProvincia
 *
 * @ORM\ManyToOne(targetEntity="GeoProvincia")
 * @ORM\JoinColumns({
 * @ORM\JoinColumn(name="provincia", referencedColumnName="id")
 * })
 */
 private $provincia;

 /**
 * Set nombre
 *
 * @param string $nombre
 * @return GeoLocalidad
 */
 public function setNombre($nombre)
 {
 $this->nombre = $nombre;

 return $this;
 }

 /**
 * Get nombre
 *
 * @return string
 */
 public function getNombre()
 {
 return $this->nombre;
 }

 /**
 * Get id
 *
 * @return integer
 */
 public function getId()
 {
 return $this->id;
 }

 /**
 * Set provincia
 *
 * @param \GeoProvincia $provincia
 * @return GeoLocalidad
 */
 public function setProvincia(\GeoProvincia $provincia = null)
 {
 $this->provincia = $provincia;

 return $this;
 }

 /**
 * Get provincia
 *
 * @return \GeoProvincia
 */
 public function getProvincia()
 {
 return $this->provincia;
 }

   }
 

en esta clase, el error nos lo estaría generando la funcion:

/**
 * Set provincia
 *
 * @param \GeoProvincia $provincia
 * @return GeoLocalidad
 */
public function setProvincia(\GeoProvincia $provincia = null)

Y lo solucionaríamos cambiando el tipo \GeoProvincia, de forma que indicasemos el namespace completo, pero solo en el parámetro, no hace falta que lo cambiemos en la anotacion. Si el namespace de provincia, igual que el de localidad es DBAL\Entity la función quedaría con esta forma:

/**
 * Set provincia
 *
 * @param \GeoProvincia $provincia
 * @return GeoLocalidad
 */
public function setProvincia(\DBAL\Entity\GeoProvincia $provincia = null)

y ojo al \ inicial!

Tambien lo podemos hacer quitando por completo el namespace, dejando la función quedaría de esta forma:

/**
 * Set provincia
 *
 * @param \GeoProvincia $provincia
 * @return GeoLocalidad
 */
public function setProvincia( GeoProvincia $provincia = null)

 
tomando esta medida en todas las clases implicadas, todo funcionará perfectamente.

24/07/2013
by carlosrobles
2 Comments

Integrar Doctrine 2 con Zend Framework 2, desde una base de datos existente.

Más o menos podemos decir que doctrine esta pensado para no pensar en el servidor de bases de datos, en tablas,  ni en nada que no sea puramente las estructuras que vamos a utilizar en la programacion.
Por tanto se suele empezar creando entidades, que después doctrine transforma en lo que corresponda en el servidor de base de datos. Estamos totalmente abstraidos de la persistencia de datos.

Para mi, que siento una especie de amor por el diseño de modelos de base de datos, esto es un poco lo contrario a lo que me gustaria.

Mi forma de empezar un proyecto suele ser primero pensar a fondo un modelo, crear un diagrama con MySql WorkBench, desde ahi obtener el script sql y ejecutarlo directamente el servidor (Database > Forward engineering) y despues sincronizar cualquier cambio entre el modelo y el servidor. Despues, obtengo las entidades y el mapeo a partir del servidor de base de datos.

Esto es algo que se hace una vez al inicio del proyecto, pero es muy probable que haya que repetirlo si hay cambios importantes en el modelo. Hay que tener en cuenta que si la base de datos es compleja (muchas relaciones entre tablas, etc) puede que el resultado no sea el esperado, y tengas que retocar el mapeo a mano. Según la documentación de doctrine, automaticamente solo encotraremos el 70-80% de la informacion necesaria. Además, y copio directamente de la documentación “the detection from an existing database cannot detect inverse associations, inheritance types, entities with foreign keys as primary keys and many of the semantical operations on associations such as cascade”

En cualquier caso, me sigue pareciendo la mejor forma de empezar para los que nos gusta tener control total sobre como se modela la base de datos.

Requisitos

Este manual está pensado para integrar con Zend Framework 2. Por tanto, tendriamos que tener instalado:

  • ZendFramework 2
  • Doctrine 2
  • Los modulos doctrine-module y doctrine-orm-module
  • Además algunos módulos de Symfony:  console y yaml

Cómo instalar doctrine y sus modulos, lo veremos facilmente en la documentación de doctrine. Los de symfony es facil que ya nos los haya instalado el composer como dependencia de algun otro, si no es asi, tendremos que investigar un poco (no quiero salirme demasiado del tema).

Este mismo tutorial serviría para hacer la ingeniería inversa a un sistema que no fuese zend. En ese caso solo necesitariamos doctrine, y tener symfony instalado.

Procedimiento

Hay distintas formas de hacerlo. Una es desde consola, y otra es desde código fuente. A mi me gusta desde consola, porque es la que nunca me ha fallado, por tanto explicaré esta.

Lo primero, creamos una carpeta y dentro creamos un archivo llamado cli-config.php, con este contenido:

<?php

//1.Configuración
 $config = new \Doctrine\ORM\Configuration();
setMetadataCacheImpl($cache);
 $config->setQueryCacheImpl($cache);

// 2.Caché
 $cache = new \Doctrine\Common\Cache\ArrayCache();
 $config->setMetadataCacheImpl($cache);
 $config->setQueryCacheImpl($cache);

// 3. Driver
$driverImpl = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(array(__DIR__.'/Entities'));
// $driverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver('./config/yml/');
//$driverImpl = new Doctrine\ORM\Mapping\Driver\XmlDriver("./config/xml/");

$config->setMetadataDriverImpl($driverImpl);

//4. Proxies
 $config->setProxyDir(__DIR__ . './Proxies');
 $config->setProxyNamespace('Proxies');

//5. Conexión
 $connectionOptions = array(

'driver'    => 'pdo_mysql',

    'host'     => 'TU_HOST',
    'port'     => '3306',
     'user'     => 'TU_USUARIO',
    'password' => 'TU_BASE_DE_DATPS',
    'dbname'   => 'TU_CONTRASEÑA',
 'mapping_types'   => array ( 'enum'   => 'string')  //ojo aqui
 );

//6. EntityManager
 $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);

/** @var $em \Doctrine\ORM\EntityManager */
$platform = $em->getConnection()->getDatabasePlatform();

$platform->registerDoctrineTypeMapping('enum', 'string');//ojo aqui

//7.HelperSet
 $helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
 ));

?>

Ahora tenemos que buscar los binarios de doctrine. En ZF los podremos encontrar en distintos sitios, segun com hayamos instalado doctrine. El sitio habitual sería aquí:
\vendor\doctrine\orm\bin

Lo que yo recomiendo es copiar directamente el archivo cli-config.php. Ademas, creamos una carpeta Entities.

Destacamos algunas cosas:

Doctrine puede utilizar distintos drivers para crear  las Classes, Classes con anotaciones o los archivos de configuración (xml, yml), en el punto 3 puedes elegir el driver. A mi me gusta hacer clases con anotaciones

Ahora abres un terminal (Inicio > ejecutar > cmd) y vas a la carpeta donde estan los binarios de doctrine y el cli-config.php, y ejecutas el comando que corresponda:
Ahora abres una terminal donde tienes el archivo y puedes ejecutar cualquiera de los siquientes comandos, segun corresponda:

Generar mapeo con xml

doctrine orm:convert-mapping --from-database xml config/xml/

Generar mapeo con yml

doctrine orm:convert-mapping --from-database yml config/yml/

Generar Classes

doctrine orm:generate-entities Entities/

Generar Classes con anotaciones

doctrine orm:generate-entities --generate-annotations=true --regenerate-entities=true Entities/

Nota:Para generar las clases es necesario que hayas generado primero los archivos de mapeo ya sea xml o yml.

Nota:Doctrine no trabaja con los tipos ENUM. Para ello lo que hacemos es un mapeo de tipos, para decirle que los tipos enum los trate como un string.  hemos visto estas lineas:

 $connectionOptions = array(

//...
'mapping_types' => array ( 'enum' => 'string')
);

$platform->registerDoctrineTypeMapping('enum', 'string');

Las dos hacen exactamente lo mismo, pero he tenido casos en distintos sistemas donde uno funciona y el otro no. Como poner los dos no supone ningun problema, suelo usar los dos aunque sea redundante.

Al terminar la ejecución, dentro de la carpeta Entities, tendras una clase para cada una de las tablas de la base de datos, y estarán preparadas para trabajar con doctrine.

Integración:

Una vez tenemos las clases, donde colocarlas en nuestro proyecto depende de cada uno. Hay gente que tiene pocas entidades, y las coloca directamente dentro del modulo que las utiliza. Esto no es una buena práctica.

A mi personalmente, me gusta agrupar la capa de acceso a datos en su propia carpeta ajena a todo lo demás. En ZF, para no complicarme demasiado, creo un módulo con todas las clases referentes al acceso a datos, como Entidades, repositorios, etc.

Para eso, creo una estructura como la que se ve:

24-07-2013 12-09-39

Es decir, dentro de module, creo un modulo de la forma habitual, le llamo DBAL (data base access layer) y dentro de src creo la carpeta DBAL, que contendra las que necesitemos, como por ejemplo Entity, Model, Repository, etc. Dentro de Entity colocaremos las clases que acabamos de crear.

Además, deberemos cambiar el namespace de cada una, para  que podamos trabajar con ellos. Siempre utilizo DBAL\Entity, para todas las entidades, para ello la primera linea de los archivos de todas las entidades debe ser:

namespace DBAL\Entity;

Ahora, le decimos ZendFramework como puede cargar todas. Primero en

config/aplication.config.php, dentro del array ‘modules’ añadimos “DBAL”

return array(
 'modules' => array(
 'DoctrineModule',
 'DoctrineORMModule',
'DBAL',
//...

y en la configuracion del modulo

/module/DBAL/config/module.config.php

le decimos a doctrine como cargar las clases del namespace DBAL\Entity, asi:

<?php
return array(

 'doctrine' => array(
 'driver' => array(
'mi_annotation_driver' => array(
 'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
 'cache' => 'array',
 'paths' => array(__DIR__ . '/../src/DBAL/Entity'),
 ),
 'orm_default' => array(
 'drivers' => array(
'DBAL\Entity' => 'mi_annotation_driver',
 ),
 ),
 ),
 )
);

Referencias:

http://jaehoo.wordpress.com/2011/11/17/ingenieria-en-inversa-en-php-con-doctrine-reverse-engineering-db/
http://parasitovirtual.wordpress.com/2011/03/07/configuracion-de-doctrine-2/
http://www.doctrine-project.org/docs/orm/2.1/en/tutorials/getting-started-xml-edition.html#a-first-prototype
http://www.doctrine-project.org/docs/orm/2.0/en/reference/tools.html
http://www.doctrine-project.org/docs/orm/2.1/en/reference/configuration.html
http://wildlyinaccurate.com/useful-doctrine-2-console-commands/

12/07/2013
by carlosrobles
0 comments

Eligiendo un proyector

 Buscando un proyector, me he dado cuenta de que hay un montón de caractéristicas, y puede que no todo el mundo tenga muy claro cuales son las importantes, que signigica cada cosa, o que es lo que tiene que buscar cuando busca un proyector
He recopilado y digerido info de distintas webs para asegurarme de que tiene coherencia y no son opiniones mias sin mas. Entre otras cosas hay información obtenida de taringa, xakata, y ebay.
No os llevará al proyector ideal, pero s servirá como guía para saber qué es cada cosa y saber que es lo que teneis que buscar para no perderos entre mil datos.

Resolución

Es la cantidad de detalle que puede mostrar un proyector y está definida por cuantos píxeles se proyectan. La resolución se expresa en pares de números, pixeles horizontales x pixeles verticales. Mientras más píxeles, mayor la resolución y mayor el nivel de detalle que podrá apreciarse en la imagen proyectada. Hasta aqui es igual que un monitor, con la diferencia de que con un proyector siempre se puede ampliar la imagen proyectada. Por tanto lo que nos interesa principalmente es lo que llaman “resolución verdadera” o “nativa”.

Tipos de resolución:

  • SVGA, o “800 x 600” – barato, pero mas limitado, más de uso domestico.
  • XGA, o “1.024 x 768” – Generalmente más caros, son un formato tan popular como la resolución a SVGA. Es el tamaño minimo a considerar para proyectar desde ipad sin limitarnos.
  • SXGA, o “1.280 x 1.024” – De alta resolución, y notablemente más costosos que XGA. Recomendados para usuarios que necesiten un proyector principalmente para conectar un ordenador, debido a qué éste requiere mayor resolución para mostrar mejor las letras y pequeños detalles.
  • UXGA, o “1.600 x 1.200” – Exclusivo para los usos a muy alta resolución que requieran detalle al máximo (generalmente PC destinados al trabajo y análisis de imágen). Relativamente pocos productos en el mercado tienen esta resolución nativa. Es más de lo que necesitariais para hacer presentaciones normales

Luminosidad

La salida de luz del proyector se mide en unidades de ANSI lúmenes.
Más lúmenes significan más brillo de la imagen proyectada, lo que a su vez se traduce en poder ver imágenes de calidad aún cuando exista mucha luz en el lugar en que se esté proyectando. Tenemos que pensar si nos interesa poer hacer presentaciones en lugares con luz, o si podemos y nos interesa bajar las persianas. Evientemente el criterio es el que más luminosidad tenga, dentro de lo que te puedas permitir. Tambien hay que tener en cuenta si tienes una buena pantalla de proyecccion, que permiten ganar nitided y brillo

  • Menos de 1000 lúmenes – Se tendrán que hacer las proyecciones en la máxima oscuridad posible.
  • 1000 a 2000 lúmenes – Ésta gama de lumenes conlleva una intensificación en el funcionamiento y el precio. Hay muchos productos de SVGA y de XGA en esta clase. Las proyecciones pueden hacerse con la iluminación del lugar, si bien al reducirla se mejora la visión de la pantalla. Generalmente la total oscuridad no es necesaria.
  • 2000 a 3000 lúmenes – Ésta es la gama de alto rendimiento en proyectores portátiles y semi-portátiles. Los productos en esta clase son convenientes para grandes salas de conferencias y clases. Ofrecen más flexibilidad en términos iluminación del lugar, puesto que la imagen es bastante brillante (una sala con luz moderada puede ser válida). También ofrecen más flexibilidad en términos de tamaño puesto que pueden iluminar una pantalla más grande sin mucha pérdida de calidad en la imagen.
  • 3000 lúmenes y más – Normalmente mas de lo necesario, considerar solo si el precio no sube mucho. Los hay hasta 12.000 lumenes, y los précios cubren una amplia gama dependiendo de otras características de funcionamiento. Se utilizan en variedad de lugares que requieren enormes pantallas, incluyendo salas de conferencias, auditorios, iglesias, conciertos, etc…

Contraste

El contraste es el cociente entre las áreas más brillantes y más oscuras de la imagen. Los cocientes del contraste deben ser altos (1000:1 o más) para conseguir la mejor imagen. Para los gráficos de ordenador y la presentación de datos, 400:1 es generalmente amplio.
La cantidad de luz que impacta en la pantalla produce que el color negro pierda intensidad. Para compensar esto, debe considerarse adquirir un proyector con el mejor contraste posible.

CONEXIONES.
Ccuantas más lleve mucho mejor, pues nos abre el abanico de cara a conectar fuentes de vídeo o información. Indispensables la conexión para el ordenador, VGA y la de S-video. Mucho mejor si añadimos la DVI y si queremos alta definición, o conectar tablets o moviles, la HDMI es   una necesidad. Tambien los hay con wifi, que nos puede resultar util si nos desplazamos y tenemos que instalarlo en distintos sitios, o si queremos hacer presentaciones desde tablet, movil, o portatil, con una comodidad mayor.

PESO:

Es importante considerar si mayormente va a estar en un lugar fijo o si va a tener que transportar.  De cara a comparar, es importante ver si las fichas indican “peso neto” o “peso bruto”

  • Entre los más normales están entre los 2 kg los mas ligeros, y los 4 los mas pesados
  • Los hay ultraligeros, o portatiles, de menos de un kilo. Suele ser a costa de perder otras caracteristicas, por tanto es importante saber las preferencias.
  • Los más profesionales, de alto desempeño y requisitos muy exigentes, pueden pesar mas de 10 kg. Suelen instalarse en el techo con idea de no moverse.

EXTRAS.
Son menos importantes pero nos pueden hacer decidirnos por un producto muy similar a otro. Por ejemplo:

  • que lleve  un buen sonido integrado (altavoces)
  • mando a distancia
  • zoom
  • mejoras digitales para la imagen
  • Distancia necesaria a la pared
  • etc.

Tecnologías

Hay distintas tecnologías que se usan en la actualidad para generar las imágenes en los proyectores. Son tres, LCD, DLP y LED.Normalmente, escogeremos proyector por el conjunto de características, no por la tecnología usada.

  • LCD: es la tecnología más antigua, y se basa en la misma filosofía que las pantallas, solo que aquí la imagen es proyectada luego.
  • DLP: son más actuales que los LCD, usan tecnologías distintas por lo que cada uno tiene sus ventajas e inconvenientes, pero en rendimiento se están acercando mucho últimamente. En este caso la imagen es creada por espejos microscópicos dispuestos en una matriz sobre un chip semiconductor, en el que cada espejo representa un píxel en la imagen proyectada.
  • LED: es la más nueva de las tres que podemos encontrar en el mercado, y se basa en la luz que emiten diodos. Las ventajas se refieren principalmente al menor consumo, mayor duración de las bombillas pero con el inconveniente de que de momento no se consiguen grandes cifras en cuanto a luminosidad, un factor como veremos determinante para escoger un proyector.

Vida util:

El caso es que al final la lámpara terminará estropeándose y eso nos generará un gasto extra. Es importante pues conjugar correctamente la vida útil con el precio que nos cuesta cambiarla, así como ver si es sencillo de hacer por nosotros mismos. En general, el precio de las lámparas suele ser elevado, algunas veces incluso por encima de un tercio del precio del proyector.

Por tanto es importante comprobar el tiempo de vida util indicado por el fabricante, que puede ir entre las 2.000 y las 6.000 horas mas o menos, sabiendo cuanto lo usamos podemos hacer el ejercicio de calcular cuantos años nos va a durar. Si no lo usamos mucho cada dia, no es muy preocupante porque cualquiera nos puede durar cinco o 10 años.

Lo que si que es importante, es tratar bien el proyector para no acortar su vida:

Consejos para mantener con vida la lámpara del proyector

  • No mover el proyector cuando la lámpara está caliente todavía.
  • Evitar el polvo, pues se fundiría antes, para lo que debemos mantener los filtros limpios y es por eso importante comprar un proyector que tenga un buen acceso a los mismos.
  • No tocar con las manos, pues la grasa podría provocar su fundido antes.
  • Mantener bien ventilado el proyector, pues el calor también precipita que el filamento se estropee.

11/07/2013
by carlosrobles
0 comments

Synchronized – Métodos sincronizados en Java

Abreis visto el modificador synchronized en distintos métodos java, voy a explicar brevemente para qué sirve.

Vemos esta clase de la documentación de oracle:

public class SynchronizedCounter {
    private int c = 0;
    public synchronized void increment() {c++;}
    public synchronized void decrement() {c--;}
    public synchronized int value() {return c;}
}

Sincronizar métodos nos permite prevenir inconsistencias cuando un objeto es accesible desde distintos hilos. Por ejemplo si un hilo incrementa el contador, mientras otro lo decrementa, y otro lo lee, puede que el resultado no sea el esperado si hay cierta concurrencia. Para eso las lecturas y escrituras de un objeto compartido, se hacen a traves de métodos sincronizados.

Esto tiene dos efectos:

  • No es posible invocar dos metodos sincronizados del mismo objeto a la vez. Si un metodo se esta ejecutando en un hilo, todos los hilos que invoquen a otro metodo se bloquean hasta que el primero termina.
  • Cuando se llama a un método sincronizado, se establece automaticamente  una relacion  happens-before con cualquier llamada a un método sincronizado de este objeto. Esto garantiza que cualquier cambio sobre el objeto es visible para cualquier hilo.

Esto es una buena base, aunque hay muchas cosas a tener en cuenta cuando hablamos de hilos y concurrencia, especialmente Deadlocks, bloqueos mutuos y ese tipo de complicaciones. Un buen punto de partida para entender conceptos es la documentacion de oracle:
http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

31/05/2013
by carlosrobles
0 comments

Visibilidad en Android

Veo que hay alguna gente que no termina de tener claro los tipos de visibilidad en Android, en lo que respecta a View.INVISIBLE y View.GONE. Voy a explicarlo, y de paso pongo el equivalente CSS que para muchos será la mejor explicación.

1. View.VISIBLE: Normal, visible.

/*equivalente CSS*/
visibility: visible; 
/*display: block; o cualquiera excepto none*/

2. View.INVISIBLE: No se ve nada, pero el componente ocupa el espacio. Es decir, se reserva un espacio vacio del tamaño del componente

/*equivalente CSS*/
visibility: hidden; 
display: block;

3. View.GONE: No se muestra ni reserva el espacio, es como si no existiese.

/*equivalente CSS*/ 
display: none;

22/05/2013
by carlosrobles
0 comments

Class ‘Locale’ not found

Estoy haciendo pruebas con Libra CMS (un CMF opensource basado en ZF2) y me encuentro este problema. Es bastante normal en Zend, y en otros sistemas, y si es un sistema que acabas de instalar, posiblemente empieces a buscar dependencias por el sitio equivocado. La clase Locale es de PHP 5, por tanto si no te la encuentra, debes empezar comprobando que tienes php 5, que tienes la extensión correspondiente instalada, o si la tienes activada.
La extension es php-intl.
Si estas en wamp, la puedes activar desde el icono de wamp en la bandeja del sistema, en PHP > PHP extensions > php-intl
Si no, puedes hacerlo directamente en tu php.ini, descomentando la linea correspondiente, (recuerda que en php.ini el punto y coma es un comentario) busca

;extension=php-intl.dll

o


;extension=php-intl.so

quita el ; y reinicia apache.

Si no funciona, o no encuentras esa linea, es probable que no tengas la extensión. Échale un ojo  a :
http://php.net/manual/es/intl.setup.php

UPDATE: puede que en tu servidor la extension se llame simplemente intl.so
UPDATE: si no puedes editar tu php.ini, a partir de 5.3 puedes considerar un phprc. diré más sobre esto en breve.

20/05/2013
by carlosrobles
0 comments

Baby Steps

En el post sobre TDD mencioné los Baby Steps, por si alguien no sabe a que me refiero con esto, lo voy a comentar, que son dos lineas:

Básicamente significa que el siguiente paso en un desarrollo debe ser lo más pequeño posible.  No debemos pensar en nuevas fases muy grandes, que son dificiles de diseñar, de estimar, y de probar de forma unitaria, si no en pasos muy pequeños que sean absolutamente triviales, y que  a su vez hacen el siguiente paso tambien trivial.

Combinado con TDD, no solo nos facilita mucho la estabilidad, sino que además dispara la productividad.

29/04/2013
by carlosrobles
0 comments

Lanzar una actividad que ya esta abierta, más atrás en la pila

En una aplicación Android, cuando estamos en una actividad, y queremos volver a la actividad que llamó a la actual, como sabemos, simplemente llamando a

finish()

termina nuestra actividad actual, y volvemos a la anterior en la pila.

Se complica más cuando queremos volver a una que no está inmediatamente atrás, por ejemplo si queremos volver a la home. Pues en realidad es igual de fácil. PAra ello creamos un intent para esa actividad, pero le añadimos el flag

FLAG_ACTIVITY_CLEAR_TOP

Que le indica  al sistema que la actividad que estamos lanzando ya está en ealidad corriendo, y en lugar de lanzar una nueva, lo que queremos es que se cierren todas las actividades que nos separen de ella, y hacerla la actual. Eso si, el intent se le entregará a la actividad vieja, como  un intent nuevo, por tanto podemos usarlo de la forma habitual para pasar datos entre actividades, o cualquiera de las posibilidades normales.

Para añadir el flag, hacemos esto:

 Intent intent = new Intent(this, ActivitySuperior.class);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);