MeetMe/Android-MultiStateView — pull request #2 by jhansche (2013-12-24 17:04:18+00:00)
Title: Fix race condition caused by delayed hiding of previous state.

The fix for #1 (race condition) also introduces a second race condition
when `setState()` is called a second time before the 1st call's previous
state view was hidden by the `Runnable`. For example:

msv.setState(ContentState.LOADING); // (1)
msv.setState(ContentState.CONTENT); // (2)

This is the simplest way to reproduce the problem. The default state is
`ContentState.CONTENT`. The (1) call shows the `LOADING` view and posts
a runnable that intends to hide the `CONTENT` view. Then the (2) call
does the opposite: shows the `CONTENT` view and posts a runnable
to hide the `LOADING` view. The (2) show happens before the (1)
runnable has a chance to hide the `CONTENT` view, so when the runnable
finally does get run, it hides the `CONTENT` view, superceding the work
done by the (2) call.

This change converts the `postRunnable()` behavior into an inner
`Handler` subclass that will take a `ContentState` obj that is meant
to be hidden. That way when `setState()` is called, we can remove any
pending messages that are meant to hide the state that is currently
requested to be shown. If however, you are switching states to a different
state, then the pending hide will still be executed properly, such as:

msv.setState(ContentState.LOADING);
msv.setState(ContentState.GENERAL_ERROR);
// will still hide CONTENT *and* will hide LOADING

This manifests easily when you set up your view to have an initial state
of `LOADING` in `onViewCreated()`, and in `onViewStateRestored()`, you
set the state back to `CONTENT`.