Friday, March 21, 2014

Load animated GIF from Internet

Previous examples show how to diaply animated GIF using decodeStream(InputStream) and decodeByteArray(InputStream) loaded from  /res/drawable/ folder. This example show how to load from Internet.



  • We cannot access Internet in main thread, such that we have to implement a background thread to load the gif from Internet.
  • Once loaded, we have to ask Android system to re-layout with updated graph.
  • In the example code, dummy delay is added to simulate network delay.
  • Both decodeStream(InputStream) and decodeByteArray(InputStream) are implemented, you can choice it by setting DECODE_STREAM true or false.
  • It can be noted that textViewInfo is filled with 0, 0 x 0; because the GIF is not loaded when onCreate() called.
  • uses-permission android:name="android.permission.INTERNET" is needed in AndroidManifest.xml
Modify activity_main.xml to added a LinearLayout to show how the system layout at run-time.
<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" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ff000090"
            android:orientation="vertical"
            android:padding="5dp" >

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

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

</LinearLayout>

GifView.java
package com.example.androidgif;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

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

public class GifView extends View {
 
 //Set true to use decodeStream
 //Set false to use decodeByteArray
    private static final boolean DECODE_STREAM = true;
 
 private InputStream gifInputStream;
 private Movie gifMovie;
 private int movieWidth, movieHeight;
 private long movieDuration;
 private long mMovieStart;
 
 final static String gifAddr = "http://3.bp.blogspot.com/-aO7sI_xlx-0/Uyhbv6BB4DI/AAAAAAAAKzg/RfKWKzg7O-M/s1600/android_er.gif";

 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(final Context context){
  setFocusable(true);

  gifMovie = null;
  movieWidth = 0;
  movieHeight = 0;
  movieDuration = 0;
  
  Thread threadLoadGif = new Thread(new Runnable(){

   @Override
   public void run() {
    try {
     URL gifURL = new URL(gifAddr);
     
     HttpURLConnection connection = (HttpURLConnection)gifURL.openConnection();
     gifInputStream = connection.getInputStream();
     
     //Insert dummy sleep
     //to simulate network delay
     try {
      Thread.sleep(3000);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     
     if(DECODE_STREAM){
      gifMovie = Movie.decodeStream(gifInputStream);
     }else{
      byte[] array = streamToBytes(gifInputStream);
            gifMovie = Movie.decodeByteArray(array, 0, array.length);
     }
     
     movieWidth = gifMovie.width();
     movieHeight = gifMovie.height();
     movieDuration = gifMovie.duration();
     
     ((MainActivity)context).runOnUiThread(new Runnable(){

      @Override
      public void run() {
       //request re-draw layout
       invalidate();
       requestLayout();
       Toast.makeText(context, 
         movieWidth + " x " + movieHeight + "\n"
         + movieDuration, 
         Toast.LENGTH_LONG).show();
      }});
     
    } catch (MalformedURLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }});
  
  threadLoadGif.start();
  
 }
 
 private static byte[] streamToBytes(InputStream is) {
        ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = is.read(buffer)) >= 0) {
                os.write(buffer, 0, len);
            }
        } catch (java.io.IOException e) {
        }
        return os.toByteArray();
    }

 @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();
            
        }
        
 }

}

Other files, MainActivity.java and AndroidManifest.xml to turn OFF hardwareAccelerated, refer to the post "Play animated GIF using android.graphics.Movie, with Movie.decodeStream(InputStream)".

(Remark: to load from Internet, uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.


Another example of playing new Google animated GIF, load from Internet.

4 comments:

PRoV said...

hi while using above code..in my project image shows blue view..can u help me how to reslove this issue

Thanking you

Andr.oid Eric said...

hello PRoV,

I cannot commit, but you can send me the link of your gif, I try to see if any reason.

What device you test on?

Krunal Patel said...

how to assign the url from the main activity.

Nitesh Singh said...

thanx sir My Apps is Succesfull by the your side.