Animated GIFs in Android is a difficult topic. It is an issue that has been discussed heavily and still, it is very difficult for developers to bring GIFs to life. There are three ways to animate GIFs on Android, each of them has its pros and cons. Each part of this series will cover one of these approaches.
Getting started
For this example, we will use an image I found on gifs.net, it’s this one:
I will store it in our project’s asset folder and name it ‘piggy.gif’. We will also use an Activity to set the views we define as content views.
Approach 1: Using Movie
Android provides the class android.graphics.Movie. This class is capable of decoding and playing InputStreams. So for this approach, we create a class GifMovieView and let it inherit from View:
Public class GifMovieView extends View
Now we create a constructor that receives a Context object and an InputStream. We provide our class a member variable which is an instance of the Movie class. We initialize this member by calling Movie.decodeStream(InputStream):
private Movie mMovie; public GifMovieView(Context context, InputStream stream) { super(context); mStream = stream; mMovie = Movie.decodeStream(mStream); }
Now that our Movie-object is initialized with our InputStrem, we just need to draw it. We can do this by calling draw(Canvas, int, int) on our Movie-object. Because we need a Canvas, we should do this in onDraw(). But before we drawing, we have to tell our object what to render. For that, we need a simple calculation to determine how much time has passed since we started the Movie. To do that, we need another member of the primitive type long, I named it mMoviestart. Now we get a timestamp, for example by calling SystemClock.uptimeMillis() or System.currentTimeMillis(). We determine how much time went by since our movie started and tell our movie to play draw the according frame. After that, we invalidate our view so that it’s redrawn:
private long mMoviestart;
@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.TRANSPARENT); super.onDraw(canvas); final long now = SystemClock.uptimeMillis();
if (mMoviestart == 0) { mMoviestart = now; }
final int relTime = (int)((now - mMoviestart) % mMovie.duration()); mMovie.setTime(relTime); mMovie.draw(canvas, 10, 10); this.invalidate(); }
All we have to do now is initialize our new View with a Context and an InputStream and set it as content view, we can do this in our Activity like this:
// ... InputStream stream = null; try { stream = getAssets().open("piggy.gif"); } catch (IOException e) { e.printStackTrace(); } GifMovieView view = new GifMovieView(this, stream); setContentView(view); // ...
That was easy, right? So where’s the contra? Well, here it is:
As you can see, the Movie-class is not able to deal with every type of animated GIFs. For some formats, the first frame will be drawn well but every other won’t. So when you walk this route, make sure your GIFs are displayed correctly.
If you want to know another, maybe better way of playing animated GIFs, stay tuned: The next part of this series will come tomorrow.
You can checkout the code of the three parts of this series at http://code.google.com/p/animated-gifs-in-android/.
As always, please feel free to leave your thoughts in the comments.