Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE in run() method of GifImageView #45

Open
ianjoneill opened this issue May 6, 2016 · 6 comments
Open

NPE in run() method of GifImageView #45

ianjoneill opened this issue May 6, 2016 · 6 comments

Comments

@ianjoneill
Copy link

Just had a crash in our app due to an NPE in the run() method of GifImageView.

Stack trace:

java.lang.NullPointerException: Attempt to invoke virtual method 'int com.felipecsl.gifimageview.library.GifDecoder.getFrameCount()' on a null object reference
    at com.felipecsl.gifimageview.library.GifImageView.void run()(GifImageView.java:130)
    at java.lang.Thread.run(Thread.java:818)

Having a look at the code, I think it's possible that this is a threading problem. I think it's possible to NPE if the following scenario occurs:

  1. startAnimation() is called, so run() is called in a new thread.
  2. run() finds that shouldClear is false.
  3. clear() is called on the main thread, so the cleanupRunnable is run almost immediately, setting gifDecoder to null.
  4. The animation thread calls gifDecoder.getFrameCount().

This seems to be a similar issue to #5.

@ianjoneill
Copy link
Author

I don't think it will fix the problem, but making the animating and shouldClear fields of the GifImageView class volatile should reduce the chances of NPE's happening, see the java tutorial on Atomic Access.

@jaredsburrows
Copy link

@ianjoneill How did you get around this?
@felipecsl Any update on this?

@ianjoneill
Copy link
Author

I never came up with a reliable test-case (I've only ever seen the crash once), but as I mentioned in my previous comment, I think marking the animating and shouldClear fields as volatile should help.

@jaredsburrows
Copy link

@ianjoneill Yes but after applying your fix, have you received this exception again?

@ianjoneill
Copy link
Author

Unfortunately I never got around to trying it out.

@mattinger
Copy link

I've gotten around this by cleaning up directly in the thread where the run method is executing. There's not a good reason that I can see for the cleanup to happen in the main UI thread. I was able to easily produce this issue, by using gifImageView in a ViewPager, and cycling rapidly forward and backward.

The problem is that since the cleanup happens in another thread, the initial condition:

if (!animating && !renderFrame) {
        break;
      }

does not actually trigger the break, but then the cleanup runs in another thread, and sets gifDecoder to null.

I also remove the "tmpBitmap" variable as well, and replaced it with an inline anonymous runnable,
as it removes another race condition:

Bitmap bitmap = gifDecoder.getNextFrame();
        if (frameCallback != null) {
          bitmap = frameCallback.onFrameAvailable(bitmap);
        }
        final Bitmap tmpBitmap = bitmap;
        frameDecodeTime = (System.nanoTime() - before) / 1000000;
        handler.post(new Runnable() {
          @Override
          public void run() {
              if (tmpBitmap != null && !tmpBitmap.isRecycled()) {
                  setImageBitmap(tmpBitmap);
              }
          }
        });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants