Android: How Do A Display A Large Animated Gif Given A Url?
Solution 1:
The general sketch of the solution is to use employ custom View
which draws asks a Movie
to draw itself to the Canvas
periodically.
The first step is building the Movie
instance. There is factory called decodeStream
that can make a movie given an InputStream
but it isn't enough to use the stream from a UrlConnection
. If you try this you will get an IOException
when the movie loader tries to call reset
on the stream. The hack, unfortunate as it is, is to use a separated BufferedInputStream
with a manually-set mark
to tell it to save enough data that reset
won't fail. Luckily, the URLConnection
can tell us how much data to expect. I say this hack is unfortunate because it effectively requires the entire image to be buffered in memory (which is no problem for desktop apps, but it is a serious issue on a memory-constrained mobile device).
Here is a snip of the Movie
setup code:
URLurl=newURL(gifSource);
URLConnectionconn= url.openConnection();
InputStreamis= conn.getInputStream();
BufferedInputStreambis=newBufferedInputStream(is);
bis.mark(conn.getContentLength());
Moviemovie= Movie.decodeStream(bis);
bis.close();
Next, you need to create a view that will display this Movie
. A subclass of View
with a custom onDraw
will do the trick (assuming it has access to the Movie
you created with the previous code).
@OverrideprotectedvoidonDraw(Canvas canvas) {
if(movie != null) {
longnow= android.os.SystemClock.uptimeMillis();
intdur= Math.max(movie.duration(), 1); // is it really animated?intpos= (int)(now % dur);
movie.setTime(pos);
movie.draw(canvas, x, y);
}
}
The view won't trigger itself to be redrawn without help, and blindly calling invalidate()
at the end of onDraw
is just an energy waste. In another thread (probably the one you used to download the image data), you can post messages to the main thread, asking for the view to be invalidated at a steady (but not insane) pace.
Handler handler = newHandler();
newThread() {
@Overridepublicvoidrun() {
// ... setup the movie (using the code from above)// ... create and display the custom view, passing the moviewhile(!Thread.currentThread().isInterrupted()) {
handler.post(newRunnable() {
publicvoidrun(){
view.invalidate();
}
});
try {
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}.start();
A really nice solution would have all sorts of sweet progress bars and error checking, but the core is here.
Solution 2:
Did you try BitmapDecode
?
There's an example in the API Demos here.
Solution 3:
Glide prove most easy and efficient way to achieve this with just one line of code :-
Glide.with(getApplicationContext())
.load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
.asGif().placeholder(R.drawable.ic_launcher).crossFade()
.into(imageView);
Result is here :-
Gif taken from here http://giphy.com/search/big-gif/3
Add jar from here :- https://github.com/bumptech/glide/releases
Solution 4:
Maybe AnimationDrawable could work for you? EDIT: Not if you want to load from a URL like this post is about. Sorry
http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
Depending on the complexity of the GIF i.e. if it is a simple loading/progress indicator you could break the GIF apart, save each image separately and use the Android Framework's AnimationDrawable.
For simple progress bars this may be less error prone, maybe even more performant.
Post a Comment for "Android: How Do A Display A Large Animated Gif Given A Url?"