public static enum LooperMode.Mode extends Enum<LooperMode.Mode>
Specifies the different supported Looper modes.
Enum Constant and Description |
---|
LEGACY
Robolectric's threading model prior to 4.3.
|
PAUSED
A new mode that more accurately models real Android's
Looper behavior,
currently in Beta. |
Modifier and Type | Method and Description |
---|---|
static LooperMode.Mode |
valueOf(String name)
Returns the enum constant of this type with the specified name.
|
static LooperMode.Mode[] |
values()
Returns an array containing the constants of this enum type, in
the order they are declared.
|
public static final LooperMode.Mode LEGACY
Scheduler
.
Scheduler
behavior can be controlled via
Scheduler.setIdleState(IdleState)
, with a default of IdleState#UNPAUSED
.
There is only a single Looper thread - with tests and all posted Looper tasks executing on
that thread.
ShadowLooper
APIs can also be used to control posted tasks,
but most of those APIs just serve as a facade to Scheduler
APIs.
There are multiple problems with this mode. Some of the major ones are:
1. The default IdleState#UNPAUSED
will executed tasks posted to a
Looper
inline synchronously. This differs from real Android behaviour, and
can cause issues with code that expects/enforces that posted tasks execute in the correct
order, such as RecyclerViews.
2. The Scheduler
list of Runnables can get out of sync with the
Looper's MessageQueue
, causing deadlocks or other race conditions.
3. Each Scheduler
keeps its own time value, which can get out of
sync.
4. Background Looper
tasks execute in the main thread, causing errors for
code that enforces that it runs on a non-main Looper
thread.public static final LooperMode.Mode PAUSED
Looper
behavior,
currently in Beta.
Conceptually LooperMode.PAUSED is similar to the LEGACY
Scheduler.IdleState.PAUSED
in the following ways:
- Tests run on the main looper thread
- Tasks posted to the main Looper
are not executed automatically, and must
be explicitly executed via ShadowLooper
APIs like
ShadowLooper.idle()
. This guarantees execution order
correctness
- SystemClock
time is frozen, and can be manually advanced via
Robolectric APIs.
However, it has the following improvements:
- Robolectric will warn users if a test fails with unexecuted tasks in the main Looper queue
- Robolectric test APIs, like
ActivityController.setup()
, will automatically
idle the main Looper
- Each Looper
has its own thread. Tasks posted to background loopers are
executed asynchronously in separate threads.
- Looper
use the real MessageQueue
to store their
queue of pending tasks
- There is only a single clock value, managed via
ShadowSystemClock
. This can be explictly incremented via
SystemClock.setCurrentTimeMillis(long)
, or
ShadowLooper.idleFor(Duration)
.
A subset of the Scheduler
APIs for the 'foreground' scheduler
are currently supported in this mode as well, although it is recommended to switch to use
ShadowLooper APIs directly.
To use:
- Apply the LooperMode(PAUSED) annotation to your test package/class/method
- Convert any background Scheduler
for controlling
Looper
s to shadowOf(looper)
- Convert any RoboExecutorService
usages to
PausedExecutorService
or
InlineExecutorService
- Run your tests. If you see an test failures like 'Main looper has queued unexecuted
runnables.', you may need to insert shadowOf(getMainLooper()).idle() calls to your test to
drain the main Looper.public static LooperMode.Mode[] values()
for (LooperMode.Mode c : LooperMode.Mode.values()) System.out.println(c);
public static LooperMode.Mode valueOf(String name)
name
- the name of the enum constant to be returned.IllegalArgumentException
- if this enum type has no constant with the specified nameNullPointerException
- if the argument is null