Tuesday, March 18, 2014

Play animated GIF using android.graphics.Movie, with Movie.decodeStream(InputStream)

This example implement a custom view, GifView, to display animated GIF using android.graphics.Movie, load movie with with Movie.decodeStream(InputStream).

Download and copy the GIF file (android_er.gif) to /res/drawable/ folder.

android_er.gif
android_er.gif

Create GifView.java extends View
package com.example.androidgif;

import java.io.InputStream;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;

public class GifView extends View {
 
 private InputStream gifInputStream;
 private Movie gifMovie;
 private int movieWidth, movieHeight;
 private long movieDuration;
 private long mMovieStart;

 public GifView(Context context) {
  super(context);
  init(context);
 }

 public GifView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init(context);
 }

 public GifView(Context context, AttributeSet attrs, 
   int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init(context);
 }
 
 private void init(Context context){
  setFocusable(true);
  gifInputStream = context.getResources()
    .openRawResource(R.drawable.android_er);
  
  gifMovie = Movie.decodeStream(gifInputStream);
  movieWidth = gifMovie.width();
  movieHeight = gifMovie.height();
  movieDuration = gifMovie.duration();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, 
   int heightMeasureSpec) {
  setMeasuredDimension(movieWidth, movieHeight);
 }
 
 public int getMovieWidth(){
  return movieWidth;
 }
 
 public int getMovieHeight(){
  return movieHeight;
 }
 
 public long getMovieDuration(){
  return movieDuration;
 }

 @Override
 protected void onDraw(Canvas canvas) {

  long now = android.os.SystemClock.uptimeMillis();
        if (mMovieStart == 0) {   // first time
            mMovieStart = now;
        }
        
        if (gifMovie != null) {

            int dur = gifMovie.duration();
            if (dur == 0) {
                dur = 1000;
            }

            int relTime = (int)((now - mMovieStart) % dur);
            
            gifMovie.setTime(relTime);

            gifMovie.draw(canvas, 0, 0);
            invalidate();
            
        }
        
 }

}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.androidgif.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/android_er"
            />

        <com.example.androidgif.GifView
            android:id="@+id/gifview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <TextView
        android:id="@+id/textinfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="info..." />

</LinearLayout>

MainActivity.java
package com.example.androidgif;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

 TextView textViewInfo;
 GifView gifView;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  gifView = (GifView)findViewById(R.id.gifview);
  textViewInfo = (TextView)findViewById(R.id.textinfo);

  String stringInfo = "";
  stringInfo += "Duration: " + gifView.getMovieDuration() + "\n";
  stringInfo += "W x H: " 
    + gifView.getMovieWidth() + " x " 
    + gifView.getMovieHeight() + "\n";
   
  textViewInfo.setText(stringInfo);

 }

}

IMPORTANT!
Modify AndroidManifest.xml to turn OFF hardwareAccelerated. Read remark on the bottom.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidgif"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidgif.MainActivity"
            android:label="@string/app_name"
            android:hardwareAccelerated="false" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



download filesDownload the files.

Related:
Play animated GIF using android.graphics.Movie, with Movie.decodeByteArray(InputStream)
Load animated GIF from Internet
Load attribute resource of android:src in XML
- updated with Run/Stop, and Repeat function
Animated GIF (Androidify) for 3D Hologram viewer, handle src attribute from xml

Added@2018-12-30:
- Display animated GIF using ImageDecoder


Remark: if android:hardwareAccelerated haven't been set "false" in AndroidManifest.xml, something will go wrong:

- Can't display the animated GIF at HTC One X:

- App stopped at Nexus 7, with error of:
Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 26494 (mple.androidgif)

15 comments:

Unknown said...

hi.. m new in android development so i have problem during run the code
error GifView Failed to instantiate

thanks for your valuable Android-er demo.

Unknown said...

Hi
I had the solution to play an animated gif, but my nexus 7 always caused a fatal error before reading your solution ^^
Thanks dude !

Anonymous said...

The final remark provides a direct solution to the problem I encountered. Thank you so much~

Unknown said...

Hi..Thank you for post.but i want to pause or stop gifView.Can you please give me a solution for that?

Unknown said...

gifInputStream = context.getResources()
.openRawResource(R.drawable.android_er);

even putting + does not help to solve this problem. an error

Unknown said...

gifInputStream = context.getResources()
.openRawResource(R.drawable.some_gif);

# some_gif cannot be resolved, it throws an error : wrong kind of resource identifier

Unknown said...

how i can pause or stop the gif animation on a last frame any idea ?
plz help

Erik said...

Please check The modified version with run/stop, and repeat version

Anonymous said...

On an emulator you have to deactivate HW acceleration in your manifest or at least
deactivate it on your view : setLayerType(View.LAYER_TYPE_SOFTWARE, null);

I tested an animated gif with the movie object (not your code, but same result)
and concluded ( android 4.4 ):
- Bad image quality (no antialias, lookss horrible )
- frame delays are not respected (0ms delay between images)
- other users noticed late starts (time to load?)

on stackoverflow i found that someone created a gif decoder with a drawable object (to lazy, not enough time to do it myself)
and it works much better :
- no need to deactivate hw acceleration
- better image quality
- full control over the framerate (by setting the delay manually)

here's the link :
http://stackoverflow.com/questions/14482415/show-gif-with-android-graphics-movie

cheers

Unknown said...

No works

Unknown said...

not work this code
after run this code
display error msg ...
unfartunately,demo hase stopped...

Shivam Kumar said...

Hello sir,
how to find gradle for

Erik said...

hello Shivam Kumar,

Sorry, what you means?

Anonymous said...

Somebody tried to run gif reverse(from end to start)? Performance is terrible. I don't know why but it seems like something with Movie class inner implementation.

Safa said...

I realized it. It's ridiculous. Did you find a solution?

>>>Anonymous said...
>>>Somebody tried to run gif reverse(from end to start)? Performance is terrible. I don't know why but it seems like something with >>>Movie class inner implementation.