Search code examples
androidrobolectricnineoldandroids

Nineoldandroids NullPointerException in AnimatorProxy with Robolectric


The view I'm testing has animation and it seems to go quite wrong when I test with Robolectric. The animation is a simple slide away using Nineoldandroids for compatibility. All works fine outside of Robolectric, however my unit test is crashing with null pointer:

10:34:35.419 [DEBUG] [TestEventLogger]     java.lang.NullPointerException
10:34:35.419 [DEBUG] [TestEventLogger]      at com.nineoldandroids.view.animation.AnimatorProxy.applyTransformation(AnimatorProxy.java:316)
10:34:35.419 [DEBUG] [TestEventLogger]      at android.view.animation.Animation.getTransformation(Animation.java:870)
10:34:35.420 [DEBUG] [TestEventLogger]      at org.robolectric.shadows.ShadowView$2.run(ShadowView.java:492)
10:34:35.420 [DEBUG] [TestEventLogger]      at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:218)
10:34:35.420 [DEBUG] [TestEventLogger]      at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:73)
10:34:35.421 [DEBUG] [TestEventLogger]      at org.robolectric.shadows.ShadowChoreographer.postCallbackDelayed(ShadowChoreographer.java:44)
10:34:35.421 [DEBUG] [TestEventLogger]      at android.view.Choreographer.postCallbackDelayed(Choreographer.java)
10:34:35.427 [DEBUG] [TestEventLogger]      at org.robolectric.shadows.ShadowView.setAnimation(ShadowView.java:487)
10:34:35.429 [DEBUG] [TestEventLogger]      at android.view.View.setAnimation(View.java)
10:34:35.431 [DEBUG] [TestEventLogger]      at com.nineoldandroids.view.animation.AnimatorProxy.<init>(AnimatorProxy.java:66)
10:34:35.432 [DEBUG] [TestEventLogger]      at com.nineoldandroids.view.animation.AnimatorProxy.wrap(AnimatorProxy.java:38)
10:34:35.432 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.PreHoneycombCompat$14.get(PreHoneycombCompat.java:161)
10:34:35.432 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.PreHoneycombCompat$14.get(PreHoneycombCompat.java:153)
10:34:35.432 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.PropertyValuesHolder.setupSetterAndGetter(PropertyValuesHolder.java:510)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.ObjectAnimator.initAnimation(ObjectAnimator.java:410)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.ValueAnimator.setCurrentPlayTime(ValueAnimator.java:538)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.ValueAnimator.start(ValueAnimator.java:928)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.ValueAnimator.start(ValueAnimator.java:951)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.ObjectAnimator.start(ObjectAnimator.java:385)
10:34:35.433 [DEBUG] [TestEventLogger]      at com.nineoldandroids.animation.AnimatorSet.start(AnimatorSet.java:502)

If I add a check in my code to only use nineoldandroids for API <11 and by default use android native animation the test passes just fine. From the nineoldandroids source I can see that it's null pointering on this line:

View view = mView.get();

where mView is mView = new WeakReference<View>(view);

Any suggestions how to work around this ideally from the test case and not my app code?


Solution

  • What seems to be happening is that the Nineoldandroid animation that animates the list element gets executed by the UI/Main looper before the AnimationProxy has fully initialised. This could be due to better simulation of the Android threading architecture in Robolectric 3.

    I resolved this by calling :

    ShadowLooper.pauseMainLooper();

    Placing this call before any method that could initiate an animation within Nineoldandroids.

    Update:

    This was causing more hassle for me and the workaround above was annoying to roll out to every bit of code that did an animation so I forked and fixed it, very small change :

    https://github.com/apinder/NineOldAndroids/commit/6d399685dc5b3932e3b806d4d7d2f27123e1ca36