¡Nexus 4 para todos!

(16 comentarios)

Da igual que te acabes de comprar un móvil, que ya tengas dos Nexus 4, o que vivas en algún lugar recóndito sin cobertura. ¿Cómo no vas a comprarte un Nexus 4 ahora que Google ha rebajado 100€ más su ya de por si escandaloso precio?

¿199€ por uno de los mejores teléfonos del mercado? ¿por un procesador quad-core y 2GB de RAM? ¿por un Android actualizado siempre a la última versión y sin capas extra que lo ralenticen? Parece mejor negocio que la famosa compra de Manhattan por unos cuantos abalorios.

¿Qué intentaba arreglar cada lenguaje de programación?

(71 comentarios)

En su artículo What Languages Fix, Paul Graham, autor de Hackers & Painters y fundador de Y Combinator examinaba hace unos años algunos de los lenguajes de programación más conocidos desde una óptica interesante: los problemas que sus creadores intentaban solucionar al crearlos.

Hoy me he vuelto a encontrar con este texto y he dedicado unos minutos a traducirlo y a crear una representación gráfica en forma de línea de tiempo que podéis ver a continuación.

[Pulsa para continuar]

Ofertaza de Wii U (y ahora, encima, pirateable)

(9 comentarios)

Aunque en España sigue costando 300€, en Amazon UK ya podemos encontrar el modelo de 8GB de Wii U por sólo 149£. 177€ al cambio. Un 40% más barato que en España.

Oferta de Wii U

¿177€ por una consola que acaba de salir? Con un precio así puedo hacerme ya con mi primera consola de octava generación, y comprar una PS4 o una XBOX 720 en el futuro.

Juegos de Wii U

Además, para hacer la oferta aún más tentadora, los creadores de Wiikey anunciaron hace unos días que ya tienen casi lista la primera solución para cargar copias de seguridad en Wii U. ¡Desde disco externo USB y sin soldaduras!

Desarrollo rápido en Android con anotaciones

(4 comentarios)

Si llevas un tiempo programando en Java recordarás esas decenas de líneas de código de inicialización y aquellos enormes XML de configuración con los que teníamos que lidiar en frameworks como Spring, JPA o JSF antes de que se popularizaran las anotaciones. En Android esa tendencia todavía no ha impuesto, pero os alegrará saber que sí existen librerías externas con las que reducir enormemente el código auxiliar y centrarnos en lo que realmente importa.

La opción más interesante es AndroidAnnotations, ya que es muy completa, no impone penalización alguna en el rendimiento y no nos obliga a que nuestras actividades extiendan de una cierta clase, lo que al carecer Java de herencia múltiple complicaría ligeramente el uso de librerías como ActionBarSherlock. ¿Suena bien? Entonces genera un proyecto con AndroidAnnotations en AndroidKickstarR y sigue leyendo; te aseguro que no te vas a arrepentir.

Asociar un layout a una actividad o fragmento

Sin AndroidAnnotations:

public class Actividad extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
    }
}

Con AndroidAnnotations podemos usar la anotación @EActivity (de enhanced activity o actividad mejorada) y pasarle el identificador del layout:

@EActivity(R.layout.actividad)
public class MyActivity extends Activity {}

De forma parecida a las actividades, con la anotación @EFragment podemos obviar el método onCreateView del fragmento. Sin AndroidAnnotations:

public class Fragmento extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento, container, false);
        return view;
    }
}

Con AndroidAnnotations:

@EFragment(R.layout.fragmento)
public class Fragmento extends Fragment {
}

Inyección de vistas

Sin AndroidAnnotations:

public class Actividad extends Activity {
	Button btnGuardar;
	EditText txtNombre;

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
		
		btnGuardar = (Button) findViewById(R.id.btnGuardar);
		txtNombre = (EditText) findViewById(R.id.txtNombre);
    }
}

Con AndroidAnnotations usaríamos la anotación @ViewById pasando como parámetro el identificador de la vista

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById(R.id.btnGuardar)
	Button btnGuardar;
	
	@ViewById(R.id.txtNombre)
	EditText txtNombre;
}

Si el nombre de la variable es igual al identificador de la vista el parámetro se puede obviar:

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById Button btnGuardar;
	@ViewById EditText txtNombre;
}

También podemos inyectar fragmentos con @FragmentById

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById Button btnGuardar;
	@ViewById EditText txtNombre;
	@FragmentById Fragmento fragmento;
}

Manipular las vistas

Si usamos @ViewById para inyectar la vistas, por la manera que tiene de funcionar AndroidAnnotations, no tendremos todavía las instancias asociadas en onCreate, por lo que si tenemos que hacer algo con las vistas tendremos que anotar uno o varios métodos con @AfterViews. Esto, que a alguno le puede parecer un incordio, a mí personalmente me gusta, porque prefiero extraer el resto del código a otros métodos siguiendo el Principio de Responsabilidad Única.

De esta forma un código como

public class Actividad extends Activity {
	TextView txtVersion;
	TextView txtFecha;

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
		
		txtVersion = (TextView) findViewById(R.id.txtVersion);
		txtFecha = (TextView) findViewById(R.id.txtFecha);
		
		establecerVersion();
		establecerFecha();
    }
	
	void establecerVersion() {
		try {
			PackageInfo infoPaquete = getPackageManager().getPackageInfo(getPackageName(), 0);
			txtVersion.setText(infoPaquete.versionName);
		} catch(NameNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	void establecerFecha() {
		DateFormat formato = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
		Date fecha = new Date();
		String strFecha = formato.format(fecha);
		txtFecha.setText(strFecha);
	}
}

se convertiría en lo siguiente

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById TextView txtVersion;
	@ViewById TextView txtFecha;
	
	@AfterViews
	void establecerVersion() {
		try {
			PackageInfo infoPaquete = getPackageManager().getPackageInfo(getPackageName(), 0);
			txtVersion.setText(infoPaquete.versionName);
		} catch(NameNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@AfterViews
	void establecerFecha() {
		DateFormat formato = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
		Date fecha = new Date();
		String strFecha = formato.format(fecha);
		txtFecha.setText(strFecha);
	}
}

Eventos

Android cuenta con un atributo XML android:onClick con el que es muy rápido y sencillo asociar un listener a un evento clic. El equivalente en AndroidAnnotations es la anotación @Click, a la que se le pasa el identificador de la vista a la que se asocia el listener (se puede obviar en caso de que el nombre del método coincida con el identificador de la vista o que sea igual pero con el sufijo Clicked).

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@Click(R.id.button1)
	void mostrarVersion() {
		// ...
	}

	@Click
	void mostrarFecha() {
		// ...
	}

	@Click
	void guardarClicked() {
		// ...
	}
}

En este caso la ventaja de las anotaciones no es tan obvia; quizás el poder ver la asociación entre la vista y el método en un golpe de vista. Tiene mayor interés el que podamos asociar listeners para unos pocos eventos más de forma igual de sencilla, con @LongClick para pulsaciones largas o @TextChange para cambios de texto.

Menús

Con la anotación @OptionsMenu podemos inflar el XML de menú, ahorrándonos sobreescribir onCreateOptionsMenu. Con @OptionsItem asociamos las distintas opciones de menú con distintos listeners, pasando el id de la opción a la anotación (también se puede obviar el id si coincide con el nombre del método, o si es igual pero con el sufijo Selected).

Versión sin anotaciones:

public class Actividad extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.actividad);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.actividad, menu);
		return true;
	}

	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.actualizar:
				actualizar();
				return true;
			case R.id.acercaDe:
				acercaDeSelected();
				return true;
			default:
			  return false;
		}
	}

	
	void actualizar() {
		// ...
	}	

	
	void acercaDeSelected() {
		// ...
	}	
}

Versión con anotaciones:

@EActivity(R.layout.actividad)
@OptionsMenu(R.menu.actividad)
public class Actividad extends Activity {
	@OptionsItem(R.id.actualizar)
	void actualizar() {
		// ...
	}	

	@OptionsItem
	void acercaDeSelected() {
		// ...
	}	
}

Inyección de recursos

Para cada tipo de recurso existe una anotación que permite inyectar dicho recurso en nuestra clase pasándole simplemente el identificador (o sin pasarle nada si el nombre del recurso coincide con el de la variable): AnimationRes, BooleanRes, ColorRes, ColorStateListRes, DimensionPixelOffsetRes, DimensionPixelSizeRes, DimensionRes, DrawableRes, HtmlRes, IntArrayRes, IntegerRes, LayoutRes, MovieRes, StringArrayRes, StringRes, TextArrayRes, TextRes.

De esta forma en lugar de:

String nombreApp = getResources().getString(R.string.nombreApp);

simplemente podríamos escribir:

@StringRes String nombreApp;

Además, en el caso concreto de que queramos obtener una cadena HTML de un archivo de recurso y establecerla como texto en un TextView, podemos llevar a cabo ambos pasos con una simple anotación @FromHtml.

Hilos de ejecución

¿Harto de usar AsyncTask o similares para ejecutar un cierto código en un hilo distinto del principal o de interfaz de usuario?

void ejecutarTareaSegundoPlano(URL urls) {
	new AsyncTask<URL, Integer, Long> {
		protected Long doInBackground(URL... urls) {
			int numUrls = urls.length;
			Long tamanyoDescarga = 0;
			for (int i = 0; i < numUrls; i++) {
				tamanyoDescarga += ClienteHttp.descargar(urls[i]);
				publishProgress((int) ((i / (float) numUrls) * 100));
			}
			return totalSize;
		}

		protected void onProgressUpdate(Integer... progreso) {
			actualizarProgreso(progreso[0]);
		}

		protected void onPostExecute(Long tamanyoDescarga) {
			mostrarDialogo("Descargados " + tamanyoDescarga[0] + " bytes");
		}
	}.execute();
}

¿Qué tal si pudieras usar la anotación @Background para indicar que un método debe ejecutarse en un hilo en segundo plano y @UiThread para que se ejecute en el hilo de interfaz de usuario? De esta forma el ejemplo anterior se reduciría a:

@Background
void descargarArchivos(URL urls) {
	int numUrls = urls.length;
	Long tamanyoDescarga = 0;
	for (int i = 0; i < numUrls; i++) {
		tamanyoDescarga += ClienteHttp.descargar(urls[i]);
		actualizarEstadoDescarga((int) ((i / (float) numUrls) * 100));
	}
	mostrarDialogoFinDescarga(tamanyoDescarga);
}

@UiThread
void actualizarEstadoDescarga(int progreso) {
	actualizarProgreso(progreso);
}

@UiThread
void mostrarDialogoFinDescarga(Long tamanyoDescarga) {
	mostrarDialogo("Descargados " + tamanyoDescarga + " bytes");
}

Guardar y recuperar el estado

Esta es otra de esas tareas repetitivas que suponen gran cantidad de código. Comparemos una implementación típica con su correspondiente versión con anotaciones.

public class Actividad extends Activity {
    Jugador jugador;
    int puntuacion;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if(savedInstanceState != null) { 
            jugador = (Jugador)savedInstanceState.getSerializable("jugador");
			puntuacion = savedInstanceState.getInt("puntuacion");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable("jugador", jugador);
        outState.putInt("puntuacion", puntuacion);
    }
}
@EActivity(R.layout.actividad)
public class Actividad extends Activity {
    @InstanceState
    Jugador jugador;

    @InstanceState
    int puntuacion;
}

Otras funcionalidades de interés

  • @Trace nos permite trazar la ejecución de un método escribiendo una entrada en el log cuando se entra y se sale del método.
  • @HierarchyViewerSupport permite utilizar la herramienta Hierarchy Viewer aunque no dispongamos de un teléfono con permisos de root o de desarrollo
  • @RoboGuice nos permite integrar AndroidAnnotation con el framework de inyección de dependencias del mismo nombre (basado en Guice, de Google)
  • @OrmLiteDao nos permite integrar AndroidAnnotation con el framework de mapeo objeto-relacional OrmLite
  • @EView y @EViewGroup facilitan la creación de vistas personalizadas
  • @SystemService nos permite inyectar un servicio del sistema


Cómo mejorar tu productivad con NetBeans en un 200%

(3 comentarios)

Decía Larry Wall, el creador de Perl, que las tres virtudes principales de un programador son la pereza, la impaciencia y el orgullo desmedido. Pereza e impaciencia suficientes para querer invertir una gran cantidad de tiempo y esfuerzo en minimizar tareas repetitivas. Y de eso es de lo que vamos a hablar hoy.

[Pulsa para continuar]

Canciones de videojuegos

(17 comentarios)

Cuando publiqué la entrada de las que, para mí, eran las 10 mejores canciones de videojuegos de la historia, me quedé con mal sabor de boca por haber dejado fuera a tantísimos de mis favoritos. Para remediarlo he montado una pequeña lista en mi adorado Spotify; tarea que, por cierto, es harto complicada al no ser tan habitual que se publicaran las bandas sonoras de los juegos antiguos.

Echadle una oída 😉

[Pulsa para continuar]

Directivo de grupo antipiratería culpable de tráfico de drogas

(5 comentarios)

Si compartes contenido en Internet eres un ladrón. Da igual que los precios no se ajusten a la realidad del mercado o que se introduzcan medidas antipiratería que no hacen más que molestar a aquellos que sí han pagado por el contenido. Simples excusas.

Directivo de grupo antipiratería culpable de tráfico de drogasToma ejemplo de Vytas Simanavicius, honrado ciudadano lituano, vicepresidente de la asociación antipiratería de su país, que no contento con dedicar sus días a la lucha contra el cáncer de la piratería, dedica sus noches al noble arte del tráfico de drogas para poder pagar por los discos de Bisbal. Un trabajador incansable, ejemplo e inspiración para todos.

Cómo añadir el código fuente de Android a Eclipse

(5 comentarios)

Cuando se programa con alguna librería o framework de terceros siempre es fundamental poder contar con su código fuente, ya sea para aprender o para ver cómo funcionan las cosas por dentro. Android no es una excepción; por eso lo primero que hago nada más instalar Eclipse con las Android Developer Tools es añadir el código fuente del SDK. De otra forma, al intentar ver el código de cualquier clase de Android Eclipse nos mostrará una pantalla similar a esta, con el código decompilado en lugar del código fuente:

[Pulsa para continuar]

Moda geek

(2 comentarios)

Al hablar de moda geek puede venirnos a la cabeza el cosplay, las camisetas con integrales y chistes informáticos, y otras curiosidades. Pero, ¿qué hacer si además de ser un amante de la cultura pop eres un fanático de la moda? ¿se puede llevar el cosplay a la vida diaria y hacerlo vistiendo bien? Esto es lo que propone Sartorial geek, dedicado, entre otras, cosas a publicar outfits inspirados en personajes tan famosos como Gandalf, Yoshi, Aqua man o el Capitán América.

Moda geek

Cómo forzar a una aplicación a utilizar una determinada interfaz de red

(8 comentarios)

En mi trabajo suelo utilizar dos redes distintas: una red WiFi, de velocidad aceptable, y una red de área local, bastante más lenta que la primera y con algunas restricciones, pero que es necesaria para conectarse a ciertos recursos y páginas de la organización. Harto de tener que activar y desactivar ambas conexiones según lo que estuviera haciendo, recurrí a Google en busca de una solución. Su nombre: ForceBindIP.

[Pulsa para continuar]

Página 8 de 282« Primero...678910...Último »