Android Rest Image and Video access application


Following are class and layout files:

1. FoodItem.java


package com.kant.gridviewsmenyudemo;

import android.graphics.Bitmap;

/**
 * @author shashi1.k1
 * 
 */
public class FoodItem {
 private Bitmap image;
 private String bitmapUrl;
 private String videoUrl;
 private String title;
 private int id;

 public FoodItem(Bitmap image, String title , int id ,String bitmapUrl,String videoUrl) {
  super();
  this.image = image;
  this.title = title;
  this.id=id;
  this.bitmapUrl=bitmapUrl;
  this.videoUrl=videoUrl;
 }

 public Bitmap getImage() {
  return image;
 }

 public void setImage(Bitmap image) {
  this.image = image;
 }

 public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }
 
 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 public String getBitmapUrl() {
  return bitmapUrl;
 }
 public void setBitmapUrl(String bitmapUrl) {
  this.bitmapUrl = bitmapUrl;
 }
 
 public String getVideoUrl() {
  return videoUrl;
 }
 public void setVideoUrl(String videoUrl) {
  this.videoUrl = videoUrl;
 }
}


2. GridViewAdapter.java

package com.kant.gridviewsmenyudemo;

import java.net.MalformedURLException;
import java.util.ArrayList;

import com.kant.gridviewsmenyudemo.ImageThreadLoader.ImageLoadedListener;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * 
 * @author shashi.k1
 * 
 */
public class GridViewAdapter extends ArrayAdapter {
 private Context context;
 private int layoutResourceId;
 private ImageThreadLoader imageLoader = new ImageThreadLoader();
 private ArrayList data = new ArrayList();

 public GridViewAdapter(Context context, int layoutResourceId,
   ArrayList data) {
  super(context, layoutResourceId, data);
  this.layoutResourceId = layoutResourceId;
  this.context = context;
  this.data = data;
 }

 private ViewHolder holder = null;

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  View row = convertView;
  holder = null;

  if (row == null) {
   LayoutInflater inflater = ((Activity) context).getLayoutInflater();
   row = inflater.inflate(layoutResourceId, parent, false);
   holder = new ViewHolder();
   holder.imageTitle = (TextView) row.findViewById(R.id.text);
   holder.image = (ImageView) row.findViewById(R.id.image);
   row.setTag(holder);
  } else {
   holder = (ViewHolder) row.getTag();
  }

  final FoodItem item = data.get(position);
  Bitmap cachedImage = null;
  try {
   cachedImage = imageLoader.loadImage(item.getBitmapUrl(),
     new ImageLoadedListener() {
      public void imageLoaded(Bitmap imageBitmap) {
       holder.image.setImageBitmap(imageBitmap);
       notifyDataSetChanged();
      }
     });
  } catch (MalformedURLException e) {
  }

  holder.imageTitle.setText(item.getTitle());
  if (cachedImage != null) {
   holder.image.setImageBitmap(cachedImage);
  }
  
  holder.image.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View view) {
    
    Intent intent = new Intent(context, VideoPLayerActivity.class);
    Bundle b = new Bundle();
    b.putString("videoUrl", item.getVideoUrl());
    intent.putExtras(b); //Put your id to your next Intent
    context.startActivity(intent);
   }
  });
  return row;
 }

 static class ViewHolder {
  TextView imageTitle;
  ImageView image;
 }
}


3. ImageThreadLoader.java

package com.kant.gridviewsmenyudemo;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.State;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.util.Log;
 
/**
 * This is an object that can load images from a URL on a thread.
 *
 * @author shashi.k1
 */
public class ImageThreadLoader {
    private static final String TAG = "ImageThreadLoader";
 
    // Global cache of images.
    // Using SoftReference to allow garbage collector to clean cache if needed
    private final HashMap> Cache = new HashMap>();
 
    private final class QueueItem {
        public URL url;
        public ImageLoadedListener listener;
    }
    private final ArrayList Queue = new ArrayList();
 
    private final Handler handler = new Handler();  // Assumes that this is started from the main (UI) thread
    private Thread thread;
    private QueueRunner runner = new QueueRunner();;
 
    /** Creates a new instance of the ImageThreadLoader */
    public ImageThreadLoader() {
        thread = new Thread(runner);
    }
 
    /**
     * Defines an interface for a callback that will handle
     * responses from the thread loader when an image is done
     * being loaded.
     */
    public interface ImageLoadedListener {
        public void imageLoaded(Bitmap imageBitmap );
    }
 
    /**
     * Provides a Runnable class to handle loading
     * the image from the URL and settings the
     * ImageView on the UI thread.
     */
    private class QueueRunner implements Runnable {
        public void run() {
            synchronized(this) {
                while(Queue.size() > 0) {
                    final QueueItem item = Queue.remove(0);
 
                    // If in the cache, return that copy and be done
                    if( Cache.containsKey(item.url.toString()) && Cache.get(item.url.toString()) != null) {
                        // Use a handler to get back onto the UI thread for the update
                        handler.post(new Runnable() {
                            public void run() {
                                if( item.listener != null ) {
                                    // NB: There's a potential race condition here where the cache item could get
                                    //     garbage collected between when we post the runnable and it's executed.
                                    //     Ideally we would re-run the network load or something.
                                    SoftReference ref = Cache.get(item.url.toString());
                                    if( ref != null ) {
                                        item.listener.imageLoaded(ref.get());
                                    }
                                }
                            }
                        });
                    } else {
                        final Bitmap bmp = readBitmapFromNetwork(item.url);
                        if( bmp != null ) {
                            Cache.put(item.url.toString(), new SoftReference(bmp));
 
                            // Use a handler to get back onto the UI thread for the update
                            handler.post(new Runnable() {
                                public void run() {
                                    if( item.listener != null ) {
                                        item.listener.imageLoaded(bmp);
                                    }
                                }
                            });
                        }
 
                    }
 
                }
            }
        }
    }
 
    /**
     * Queues up a URI to load an image from for a given image view.
     *
     * @param uri   The URI source of the image
     * @param callback  The listener class to call when the image is loaded
     * @throws MalformedURLException If the provided uri cannot be parsed
     * @return A Bitmap image if the image is in the cache, else null.
     */
    public Bitmap loadImage( final String uri, final ImageLoadedListener listener) throws MalformedURLException {
        // If it's in the cache, just get it and quit it
        if( Cache.containsKey(uri)) {
            SoftReference ref = Cache.get(uri);
            if( ref != null ) {
                return ref.get();
            }
        }
 
        QueueItem item = new QueueItem();
        item.url = new URL(uri);
        item.listener = listener;
        Queue.add(item);
 
        // start the thread if needed
        if( thread.getState() == State.NEW) {
            thread.start();
        } else if( thread.getState() == State.TERMINATED) {
            thread = new Thread(runner);
            thread.start();
        }
        return null;
    }
 
    /**
     * Convenience method to retrieve a bitmap image from
     * a URL over the network. The built-in methods do
     * not seem to work, as they return a FileNotFound
     * exception.
     *
     * Note that this does not perform any threading --
     * it blocks the call while retrieving the data.
     *
     * @param url The URL to read the bitmap from.
     * @return A Bitmap image or null if an error occurs.
     */
    public static Bitmap readBitmapFromNetwork( URL url ) {
        InputStream is = null;
        BufferedInputStream bis = null;
        Bitmap bmp = null;
        try {
            URLConnection conn = url.openConnection();
            conn.connect();
            is = conn.getInputStream();
            bis = new BufferedInputStream(is);
            bmp = BitmapFactory.decodeStream(bis);
        } catch (MalformedURLException e) {
            Log.e(TAG, "Bad ad URL", e);
        } catch (IOException e) {
            Log.e(TAG, "Could not get remote ad image", e);
        } finally {
            try {
                if( is != null )
                    is.close();
                if( bis != null )
                    bis.close();
            } catch (IOException e) {
                Log.w(TAG, "Error closing stream.");
            }
        }
        return bmp;
    }
 
}

4. MainActivity.java

package com.kant.gridviewsmenyudemo;

import java.util.ArrayList;

import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.Toast;

/**
 * 
 * @author shashi.k1
 * 
 */
public class MainActivity extends Activity {
 private GridView gridView;
 private GridViewAdapter customGridAdapter;
 private static String restURL = "http://107.110.1.125:8080/TestRestApplication/kantServer/webservice/fooditems/";
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  gridView = (GridView) findViewById(R.id.gridView);
  customGridAdapter = new GridViewAdapter(this, R.layout.row_grid,
    getData());
  gridView.setAdapter(customGridAdapter);

  gridView.setOnItemClickListener(new OnItemClickListener() {
   public void onItemClick(AdapterView parent, View v,
     int position, long id) {
    Toast.makeText(MainActivity.this, position + "#Selected",
      Toast.LENGTH_SHORT).show();
   }

  });

 }

 /**
  * 
  * @return
  */
 private ArrayList getData() {
  final ArrayList imageItems = new ArrayList();
  // retrieve String drawable array
  for (int i = 1; i <= 4; i++) {
   //ImageItem item=getImageItemFromServer();
   imageItems.add(new FoodItem(null, "Image#" + i, i,(restURL + i + "/image"),(restURL + i + "/video")));
  }

  return imageItems;

 }

 

 
}


5. VideoPLayerActivity.java

package com.kant.gridviewsmenyudemo;

import java.io.File;
import java.net.MalformedURLException;

import com.kant.gridviewsmenyudemo.VideoThreadLoader.VideoLoadedListener;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.widget.MediaController;
import android.widget.VideoView;

public class VideoPLayerActivity extends Activity {
 String videoUrl;
 VideoView videoView;
 private VideoThreadLoader videoLoader = new VideoThreadLoader();

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_video_player);
  videoView = (VideoView) findViewById(R.id.videoView1);
  this.videoUrl = getIntent().getExtras().getString("videoUrl");
  try {
   videoLoader.loadVideo(videoUrl, new VideoLoadedListener() {
    @Override
    public void videoLoaded(File imageBitmap) {
     onDownloadFinished();
    }
   });
  } catch (MalformedURLException e) {
  }

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.video_player, menu);
  return true;
 }

 public void onDownloadFinished() {
  MediaController mc = new MediaController(this);
  mc.setAnchorView(videoView);
  mc.setMediaPlayer(videoView);
  videoView.setMediaController(mc);
  // video.setVideoURI(Uri.parse("http://www.youtube.com/watch?v=Eb5uaCHchWw"));
  videoView.setVideoPath(Environment.getExternalStorageDirectory()
    .getAbsolutePath() + "/video.mp4");
  videoView.start();
 }

}


6. VideoThreadLoader.java

package com.kant.gridviewsmenyudemo;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.State;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.http.util.ByteArrayBuffer;

import android.os.Environment;
import android.os.Handler;
import android.util.Log;

public class VideoThreadLoader {

 private static final String TAG = "VideoThreadLoader";

 // Global cache of images.
 // Using SoftReference to allow garbage collector to clean cache if needed
 private final HashMap> Cache = new HashMap>();

 private final class QueueItem {
  public URL url;
  public VideoLoadedListener listener;
 }

 private final ArrayList Queue = new ArrayList();

 private final Handler handler = new Handler(); // Assumes that this is
             // started from the main
             // (UI) thread
 private Thread thread;
 private QueueRunner runner = new QueueRunner();;

 /** Creates a new instance of the ImageThreadLoader */
 public VideoThreadLoader() {
  thread = new Thread(runner);
 }

 /**
  * Defines an interface for a callback that will handle responses from the
  * thread loader when an image is done being loaded.
  */
 public interface VideoLoadedListener {
  public void videoLoaded(File imageBitmap);
 }

 /**
  * Provides a Runnable class to handle loading the image from the URL and
  * settings the ImageView on the UI thread.
  */
 private class QueueRunner implements Runnable {
  public void run() {
   synchronized (this) {
    while (Queue.size() > 0) {
     final QueueItem item = Queue.remove(0);

     // If in the cache, return that copy and be done
     if (Cache.containsKey(item.url.toString())
       && Cache.get(item.url.toString()) != null) {
      // Use a handler to get back onto the UI thread for the
      // update
      handler.post(new Runnable() {
       public void run() {
        if (item.listener != null) {
         // NB: There's a potential race condition
         // here where the cache item could get
         // garbage collected between when we post
         // the runnable and it's executed.
         // Ideally we would re-run the network load
         // or something.
         SoftReference ref = Cache
           .get(item.url.toString());
         if (ref != null) {
          item.listener.videoLoaded(ref.get());
         }
        }
       }
      });
     } else {
      final File bmp = readVideoFromNetwork(item.url);
      if (bmp != null) {
       Cache.put(item.url.toString(),
         new SoftReference(bmp));

       // Use a handler to get back onto the UI thread for
       // the update
       handler.post(new Runnable() {
        public void run() {
         if (item.listener != null) {
          item.listener.videoLoaded(bmp);
         }
        }
       });
      }

     }

    }
   }
  }
 }

 /**
  * Queues up a URI to load an image from for a given image view.
  * 
  * @param uri
  *            The URI source of the image
  * @param callback
  *            The listener class to call when the image is loaded
  * @throws MalformedURLException
  *             If the provided uri cannot be parsed
  * @return A Bitmap image if the image is in the cache, else null.
  */
 public File loadVideo(final String uri, final VideoLoadedListener listener)
   throws MalformedURLException {
  // If it's in the cache, just get it and quit it
  if (Cache.containsKey(uri)) {
   SoftReference ref = Cache.get(uri);
   if (ref != null) {
    return ref.get();
   }
  }

  QueueItem item = new QueueItem();
  item.url = new URL(uri);
  item.listener = listener;
  Queue.add(item);

  // start the thread if needed
  if (thread.getState() == State.NEW) {
   thread.start();
  } else if (thread.getState() == State.TERMINATED) {
   thread = new Thread(runner);
   thread.start();
  }
  return null;
 }

 private final static String PATH = Environment
   .getExternalStorageDirectory().getAbsolutePath();

 /**
  * Convenience method to retrieve a bitmap image from a URL over the
  * network. The built-in methods do not seem to work, as they return a
  * FileNotFound exception.
  * 
  * Note that this does not perform any threading -- it blocks the call while
  * retrieving the data.
  * 
  * @param url
  *            The URL to read the bitmap from.
  * @return A Bitmap image or null if an error occurs.
  */
 public static File readVideoFromNetwork(URL url) {
  InputStream is = null;
  BufferedInputStream bis = null;
  File file = null;
  try {

   file = new File(PATH + "/video.mp4");

   // long startTime = System.currentTimeMillis();
   /* Open a connection to that URL. */
   URLConnection ucon = url.openConnection();

   /*
    * Define InputStreams to read from the URLConnection.
    */
   is = ucon.getInputStream();
   bis = new BufferedInputStream(is);

   /*
    * Read bytes to the Buffer until there is nothing more to read(-1).
    */
   ByteArrayBuffer baf = new ByteArrayBuffer(10000);
   int current = 0;
   while ((current = bis.read()) != -1) {
    baf.append((byte) current);
   }

   /* Convert the Bytes read to a String. */
   FileOutputStream fos = new FileOutputStream(file);
   fos.write(baf.toByteArray());
   fos.close();
  } catch (MalformedURLException e) {
   Log.e(TAG, "Bad ad URL", e);
  } catch (IOException e) {
   Log.e(TAG, "Could not get remote video", e);
  } finally {
   try {
    if (is != null)
     is.close();
    if (bis != null)
     bis.close();
   } catch (IOException e) {
    Log.w(TAG, "Error closing stream.");
   }
  }
  return file;
 }

}


7. activity_main.xml



    

        
    

    
    



8. activity_video_player.xml



    

    



9. row_grid.xml



    
    

    
    


Note: Next Post on Rest server Code and JAX-RS basics.

Comments