0

Please excuse me if this is simple to resolve. I'm really new to debugging and resolving situations like this. I'm really not sure where to begin to start tracking down this issue and sure of the architecture involved. It happens sporadically and seems more of like a race condition based on how fast I try to refire up the animation after the previous animation ended. Greatly appreciate any pointers and learn a little.

08-08 09:26:01.410 30626-30626/com.myapp.myappname E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.myappname, PID: 30626
java.lang.NullPointerException: Attempt to invoke interface method 'void android.animation.Animator$AnimatorListener.onAnimationEnd(android.animation.Animator)' on a null object reference
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1239)
at android.animation.ValueAnimator.cancel(ValueAnimator.java:1140)
at android.animation.ObjectAnimator.animateValue(ObjectAnimator.java:974)
at android.animation.ValueAnimator.animationFrame(ValueAnimator.java:1384)
at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1427)
at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:759)
at android.animation.ValueAnimator$AnimationHandler$1.run(ValueAnimator.java:801)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
at android.view.Choreographer.doCallbacks(Choreographer.java:695)
at android.view.Choreographer.doFrame(Choreographer.java:628)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Here is some reference code regarding the mechanics of what is causing the NPE. Essentially I have a start and a stop button to register and unregister a light sensor. When registered and a light event happens I allow one call at a time via a lock and startup a handler/runnable. When the animation ends/completes the lock is released for another execution in the light event handler.

Where I see the NPE happening sporadically is when I go to press START after a prior STOP was issued. It happens rarely, right at the boundary of a STOP happening and START happening again.

// on startup of app, prepare runnable
runnableAlpha = new Runnable()
{
    @Override
    public void run()
    {
        try
        {
            final float newAlpha = (.10f * (mLastLightValue / (mLightSensor.getMaximumRange() / 100)));
            final ObjectAnimator oa = ObjectAnimator.ofFloat(mMyAppRatingBar, "alpha", mMyAppRatingBarLastAlpha, newAlpha);

            oa.addListener(new AnimatorListener()
            {
                @Override
                public void onAnimationStart(Animator animation)
                {
                }

                @Override
                public void onAnimationEnd(Animator animation)
                {
                    try
                    {
                        oa.addListener(null);
                        oa.addUpdateListener(null);
                        mMyAppRatingBarLastAlpha = newAlpha;
                    }
                    catch (Exception e1)
                    {
                        // do nothing
                    }
                    finally
                    {
                        try
                        {
                            mTweenLock.release();
                        }
                        catch (Exception e1)
                        {
                            // do nothing
                        }
                    }
                }

                @Override
                public void onAnimationCancel(Animator animation)
                {
                    try
                    {
                        oa.addListener(null);
                        oa.addUpdateListener(null);
                        mMyAppRatingBarLastAlpha = newAlpha;
                    }
                    catch (Exception e1)
                    {
                        // do nothing
                    }
                    finally
                    {
                        try
                        {
                            mTweenLock.release();
                        }
                        catch (Exception e1)
                        {
                            // do nothing
                        }
                    }
                }

                @Override
                public void onAnimationRepeat(Animator animation)
                {
                }
            });

            oa.setInterpolator(new DecelerateInterpolator());
            oa.setDuration(1000);
            oa.start();

            try
            {
                if (mAlphaHandler != null)
                {
                    mAlphaHandler.removeCallbacks(runnableAlpha);
                }
            }
            catch (Exception e1)
            {
                // do nothing
            }
            finally
            {
                mAlphaHandler = null;
            }
        }
        catch(Exception e)
        {
            try
            {
                mTweenLock.release();
            }
            catch (Exception e1)
            {
                // do nothing
            }
        }
    }
}


// wire up handler and runnable only if light sensor registered, light event triggered, no current lock(prior light event being handled)
public void onSensorChanged(SensorEvent event)
{
    if(!mTweenLock.tryAcquire())
    {
        return;
    }

    try
    {
        mAlphaHandler = new Handler();
        mLastLightValue = event.values[0];

        mAlphaHandler.postDelayed(runnableAlpha, 0);
    }
    catch(Exception e)
    {
        mAlphaHandler = null;
        mTweenLock.release();
    }
}

// when we press START button in app, fire up the light sensor to begin work
mSensorManager = (SensorManager) mContext.getSystemService(mContext.SENSOR_SERVICE);
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

if(mLightSensor == null)
{
    mSensorManager = null;
    return;
}

mSensorManager.unregisterListener(this, mLightSensor);  // clear out prior if existent
mSensorManager.registerListener(this, mLightSensor, SensorManager.SENSOR_DELAY_UI);

// when we press STOP button in app, we force teardown of everything
try
{
    if(mAlphaHandler != null)
    {
        mAlphaHandler.removeCallbacksAndMessages(null);
        mAlphaHandler = null;
        runnableAlpha = null;
    }
}
catch(Exception e1)
{
    // do nothing
}
Matt
  • 74,352
  • 26
  • 153
  • 180
Captain Kirk
  • 350
  • 6
  • 24
  • Let me know what code you would like to see. Assuming just the setup and teardown of the animation? – Captain Kirk Aug 08 '16 at 17:10
  • Yeah, and animation too – Denis Sologub Aug 08 '16 at 17:11
  • Seeing as the error is inside the `android.animation` package, I'm not sure you can just "set a breakpoint" there. It would be useful to see how you setup the animator, though – OneCricketeer Aug 08 '16 at 17:12
  • @cricket_007 `the error is inside the android.animation package` It's actually **not**. The error is generated by *invoking a method* on a non instantiated object - As usual, with NPEs. – Phantômaxx Aug 08 '16 at 17:29
  • @Rotwang Could you explain, then "Attempt to invoke `` on null reference **at** `android.animation...`"? Or are you saying there is more to the stacktrace? – OneCricketeer Aug 08 '16 at 17:31
  • @cricket_007 Simply the user tried to use that method on that type of object. But the object was not instanced. Maybe not even declared (whi knows, without seeing a line of code?). Please go through this post. http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it – Phantômaxx Aug 08 '16 at 17:33
  • @Rotwang I'm at least trying to solve the problem rather than go on a closing spree... I've read that post, and I'm tired of flagging it unless it's a really obvious problem. I've read that a lot as well as this post. http://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors – OneCricketeer Aug 08 '16 at 17:35
  • @cricket_007 I added substance to my previous comment. Closing duplicate posts is a must. And every NPE-related post is a duplicate. – Phantômaxx Aug 08 '16 at 17:36
  • @Rotwang Could you then explain why the error "happens sporadically" and not "continuously"? – OneCricketeer Aug 08 '16 at 17:38
  • @cricket_007 Sincerely... are you kidding me? I can't guess the code, I'm not the developer, I cannot debug it... the variables in play are so many. I can only tell you that "EVERY NPE ORIGINATES FROM AN OBJECT USED BEFORE IT HAS BEEN INSTANCED". And that's **always** true. – Phantômaxx Aug 08 '16 at 17:42
  • @cricket_007 I added some code to give insight into what i'm doing. A lot of this is new to me so maybe there is something glaringly wrong in my approach? – Captain Kirk Aug 08 '16 at 18:08
  • I'm not too familiar with the mechanics of the animation library, but `oa.addListener(null);` seems like it could cause a problem – OneCricketeer Aug 08 '16 at 18:13
  • I've seen a lot of people recommending that to ensure the listener is cleared out. – Captain Kirk Aug 08 '16 at 18:25
  • @Rotwang Hi Rotwang. I've already reviewed the link you posted that this post is a duplicate of before I wrote this post. It did not answer my question. I completely understand how to read a stack trace and how to pinpoint code regions, but i'm having trouble with this as the call stack is pointing at the fault happening in android.animation. I didn't see your link discussing how to resolve issues in that instance. – Captain Kirk Aug 08 '16 at 18:44
  • Glad you solved the issue. The "pulling" of a closed question has to go through a voting queue. And now you understand why I was arguing against closing the question ;) – OneCricketeer Aug 08 '16 at 22:30
  • @cricket_007 Thank you for writing and defending the point on this one. Great appreciated! – Captain Kirk Aug 08 '16 at 22:33
  • @Rotwang Hi Rotwang. Please remove the duplicate link from this POST if you have the ability to do so. Also please allow people to sort out their issues and accumulate advice before stabbing posts with duplicate taking them off the viewing radar. – Captain Kirk Aug 08 '16 at 22:35
  • This **is** a duplicate. Why should I remove the mark? The question is still visible, until it's deleted. – Phantômaxx Aug 09 '16 at 06:31
  • I'm sorry you feel that way. Your link does not answer the question. Its a generic answer to a specific problem that I answered with specifics. See the updated comments in the post. In the meantime I've flagged this for the moderators to get involved. – Captain Kirk Aug 09 '16 at 06:46

1 Answers1

0

The issue turned out to be .onAnimationCancel() intermittently being called wherein 'oa' was being set to null and .onAnimationEnd() being subsequently called after .onAnimationCancel() which is how the architecture works. When .onAnimationEnd was called, 'oa' at that point is NULL causing this NPE. Since .onAnimationEnd() is guaranteed to be called in both cases, the .onAnimationCancel() was pulled resolving the NPE.**

Captain Kirk
  • 350
  • 6
  • 24