Event-driven programming for Android (Part I)

(This is the first article in a three-part series)

Although Android includes some event-driven features in its development, it is far away from being a pure event-driven architecture. Is this something good or bad? As in every issue with software development the answer is not easy: it depends.

First, let’s establish a definition for event-driven development. This is a programming paradigm where the flow of execution is determined by events triggered by actions (such user interaction, messaging from other threads, etc). In this sense, Android is partially event-driven: we all can think of the onClick listeners or the Activity lifecycle, which are events able to trigger actions in an application. Why I said it is not a pure event-driven system? By default, each event is bound to a particular controller, and it is difficult to operate besides it (for example, the onClick events are defined for a view, having a limited scope).

Wait, you are talking about a new programming paradigm. Adopting frameworks or methodologies has always a cost, could this bring any advantage? I say yes, and to show it I want to present some limitations with traditional Android development.

In many scenarios will be easy to end up with a structure as the following diagram is showing:

androidstatusquo

 

Activities can communicate with Fragments, Fragments can send messages to another Fragments and Services. There is a tight coupling of components, and applying changes can be expensive(*). This leads frequently to boilerplate code, interfaces that implement functions that need to callback and propagate through different layers… you probably know where I want to go. As the amount of code increases, the maintainability and good software engineering practices are decreasing.

How event-driven programming applies here? Let’s represent another system proposal:

androidevent

Conceptually, the represented system have an event bus. There are different entities subscribed to the Event Bus, and posting events or listening to events – being respectively a producer or a consumer. Any subscriber can perform an action without knowing the logic. Think about it. Think about particular possibilities: a Fragment could render again and update its screen without knowing the logic behind any operation, just knowing that an event took place. Think about the possibilities of decoupling code and having a clean, compartmentalized architecture.

Is this paradigm supported in Android? Well, partially. As mentioned, the SDK offers natively a reduced set of event handling techniques, but we we want to go further. There are some names I want to mention here:

  • EventBus, from greenrobot. This library has been optimized for Android, and has some advanced features like delivery threads and subscriber priorities.
  • Otto, from Square. Originally a fork from Guava, it has evolved and being refined to the Android platform.

Having tried both I prefer EventBus over Otto. Greenrobot claims that EventBus is significantly better at performing than its pair, and provides an extra amount of features.

Screen Shot 2015-01-25 at 9.57.52 PM

Screen Shot 2015-01-25 at 10.00.04 PM

 

The next article will explore how to implement basic functions in EventBus

(*) I deliberately like to use the word “expensive” when referring to “lot of time”. Thinking in economical terms is frequently more effective.

Testing Asynchronous Tasks on Android

Recently, at Sixt we have been migrating our development environment from Eclipse to Android Studio. This has mean we have also moved to the new build system, Gradle, and applying TDD and CI to our software development process. This is not the place to discuss the benefits of applying CI to a software development plan, but to talk about a problem arising when testing tasks running on different threads than the UI in Android.

 

A test in Android is (broad definition) an extension of a JUnit Suitcase. They do include setUp() and tearDown() for initialization/closing the tests, and infers using reflection the different test methods (starting with JUnit 4 we can use annotations to specify the priority and execution of all the tests). A typical test structure will look like:

public class MyManagerTest extends ActivityTestCase {

	public MyManagerTest(String name) {
		super(name);
	}

	protected void setUp() throws Exception {
		super.setUp();
	}

	protected void tearDown() throws Exception {
		super.tearDown();
	}

	public void testDummyTest() {
		fail("Failing test");
	}

}

This is a very obvious instance: in a practical case we would like to test things such as HTTP requests, SQL storage, etc. In Sixt we follow a Manager/Model approach: each Model contains the representation of an Entity (a Car, a User…) and each Manager groups a set of functionality using different models (for example, our LoginManager might require of models Users to interact with them). Most our managers perform HTTP  requests intensively in order to retrieve data from our backend. As an example, we would perform the login of a user using the following code:

 

	mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() {
		@Override
		public void onFailure(Throwable throwable) {
			fail();
		}

		Override
		public void onSuccess(User customer) {
		//..
		}
	});

When it comes to apply this to our own test suitcase, we just make the process fail() when the result does not work as we were expecting. We can see why in the method onFailure() we call to fail().

However, even if I was using a wrong username the test was still passing. Wondering around, seems that the test executed the code sequentially, and did not wait until the result of the callbacks was back. This is certainly a bad approach, since a modern application do intense usage of asynchronous tasks and callback methods to retrieve data from a backend!. Tried applying the @UiThreadTest bust still didn’t work.

I found the following working method. I simply use CountDownLatch signal objects to implement the wait-notify (you can use synchronized(lock){… lock.notify();}, however this results in ugly code) mechanism. The previous code will look like follows:

	final CountDownLatch signal = new CountDownLatch(1);
	mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() {
		@Override
		public void onFailure(Throwable throwable) {
			fail();
			signal.countDown();
		}

		Override
		public void onSuccess(User customer) {
			signal.countDown();
		}
	});
	signal.await();

 

A high-entropy randomness generator

 

This cartoon of Dilbert always has always fascinated me. You can never be sure about randomness, since the concept itself of randomness provides uncertainty to the process. A few years ago, I even wrote a post on how to achieve randomness using deterministic methods. Nowadays, entropy can always be improved to obtain a more accurate (in this case would be more appropriate to say “less accurate” instead) result.  This can lead into many philosophical discussions, which are not my purpose.

The traditional approach has been to take contextual information (such as the UNIX time) to create a seed for the algorithm and give more uncertainty to the process. This might be sufficient for 99% of our purposes, but leads to more complex problems: For instance, is easy to determine when a user logged into a system, and if at this time a random number is generated to, at the same time, generate some cryptographic keys, is easy to establish an interval when the user was logged (and therefore being closer to the seed of the random algorithm). Is still difficult to determine accurately the exact time, but definitely not impossible: systems of huge relevance face this problem daily.

Recently a publish in the Android Market Chinese Radicals, a program to learn Chinese. Since I need to choose randomly the Chinese radicals for the program, I decided to use it as a testbed to extend my experiment from 3 years ago. The approach is using some “contextualization” of the seed, and combining it with a probability density function. The explanation can get really complex, but I’ll try to summarize:

  1. At a certain point of execution, I categorize the accesible memory of the thread where the software is running (size and number of memory blocks). This information is stored and modeled for the density function.
  2. Afterwards, I take the UNIX time of the system. I apply a probability distribution to the model saved in the first step, and then combine it with this second point. I store the current time, and apply a first pass.
  3. When the generation of the random number is finished, I determine the difference between that time and the time I stored in the step two. Since the memory information saved in the point 1 (the entropy of the system) might differ, this time will likely be different. Then I apply a second pass to generate, with more certainty, the random number.

 

I have released this generator as a Java .jar. You can include in any Java project (Swing, Blackberry, Android, etc). You can download it from here. It works as follows:

  1. Import the jar
  2. Import the class com.randomizator.Randomizator, and create an object Randomizator by using Randomizar myObject = new Randomizator();
  3. Using randomizator.getInt( interval ) will return you a random number between 0 and the number provided.

So far only the generation of integer values is supported. Please, check it out and let me know what you think.

 

JRE cannot be found

Actualicé mi versión de JDK y me versión de Eclipse todo al mismo tiempo. Intuía ligeramente que podría darme algún problema realizarlo de manera simultánea. Tras la actualización (incluyendo la descarga de todas las actualizaciones del proyecto Calipso, WPA y otros) , quería depurar una aplicación web, así que cambie a la perspectiva J2EE e intenté inicializar Tomcat desde el panel del servidor. Recibí este amistoso mensaje de error:
The JRE could not be found. Edit the server and change the JRE location.

La manera de solucionarlo es la siguiente: Preferencias desde el menú Window, expandir la opción server, seleccionar Installed Runtimes. Posiblemente, se haya quedado activada la opción Workbench default JRE. Deberás cambiarla manualmente desde esta misma localización a la que estés utilizando para que todo funcione. No obstante, esto significa que Eclipse no es capaz de reconocer estos cambios de JDK/JRE, así que deberás tenerlo en cuenta cada vez que actualices alguna de las aplicaciones relatadas.

Saludos.