Sunday, November 22, 2009

Displaying Images from SD Card In Android - Part 2

In one of my previous posts, I wrote about how to fetch and display images from the SD card. The problem with the previous post is that one would have to wait until the first couple of images are available and shown on the screen. This implies that when the user wants to see the images, he will wait a couple of seconds until the first screen of images is available. The code that I'm going to post here works more like the Gallery application, meaning that one image at a time will be displayed on the screen. To achieve this effect, I used an AsyncTask, which fetches one image at a time in the background, and adds that image to the grid view during the progress update.

package blog.android.sdcard2;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;

/**
 * Loads images from SD card. 
 * 
 * @author Mihai Fonoage
 *
 */
public class LoadImagesFromSDCardActivity extends Activity implements
OnItemClickListener {
    
    /**
     * Grid view holding the images.
     */
    private GridView sdcardImages;
    /**
     * Image adapter for the grid view.
     */
    private ImageAdapter imageAdapter;
    /**
     * Display used for getting the width of the screen. 
     */
    private Display display;

    /**
     * Creates the content view, sets up the grid, the adapter, and the click listener.
     * 
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        // Request progress bar
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.sdcard);

        display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        setupViews();
        setProgressBarIndeterminateVisibility(true); 
        loadImages();
    }

    /**
     * Free up bitmap related resources.
     */
    protected void onDestroy() {
        super.onDestroy();
        final GridView grid = sdcardImages;
        final int count = grid.getChildCount();
        ImageView v = null;
        for (int i = 0; i < count; i++) {
            v = (ImageView) grid.getChildAt(i);
            ((BitmapDrawable) v.getDrawable()).setCallback(null);
        }
    }
    /**
     * Setup the grid view.
     */
    private void setupViews() {
        sdcardImages = (GridView) findViewById(R.id.sdcard);
        sdcardImages.setNumColumns(display.getWidth()/95);
        sdcardImages.setClipToPadding(false);
        sdcardImages.setOnItemClickListener(LoadImagesFromSDCardActivity.this);
        imageAdapter = new ImageAdapter(getApplicationContext()); 
        sdcardImages.setAdapter(imageAdapter);
    }
    /**
     * Load images.
     */
    private void loadImages() {
        final Object data = getLastNonConfigurationInstance();
        if (data == null) {
            new LoadImagesFromSDCard().execute();
        } else {
            final LoadedImage[] photos = (LoadedImage[]) data;
            if (photos.length == 0) {
                new LoadImagesFromSDCard().execute();
            }
            for (LoadedImage photo : photos) {
                addImage(photo);
            }
        }
    }
    /**
     * Add image(s) to the grid view adapter.
     * 
     * @param value Array of LoadedImages references
     */
    private void addImage(LoadedImage... value) {
        for (LoadedImage image : value) {
            imageAdapter.addPhoto(image);
            imageAdapter.notifyDataSetChanged();
        }
    }
    
    /**
     * Save bitmap images into a list and return that list. 
     * 
     * @see android.app.Activity#onRetainNonConfigurationInstance()
     */
    @Override
    public Object onRetainNonConfigurationInstance() {
        final GridView grid = sdcardImages;
        final int count = grid.getChildCount();
        final LoadedImage[] list = new LoadedImage[count];

        for (int i = 0; i < count; i++) {
            final ImageView v = (ImageView) grid.getChildAt(i);
            list[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
        }

        return list;
    }
    /**
     * Async task for loading the images from the SD card. 
     * 
     * @author Mihai Fonoage
     *
     */
    class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {
        
        /**
         * Load images from SD Card in the background, and display each image on the screen. 
         *  
         * @see android.os.AsyncTask#doInBackground(Params[])
         */
        @Override
        protected Object doInBackground(Object... params) {
            //setProgressBarIndeterminateVisibility(true); 
            Bitmap bitmap = null;
            Bitmap newBitmap = null;
            Uri uri = null;            

            // Set up an array of the Thumbnail Image ID column we want
            String[] projection = {MediaStore.Images.Thumbnails._ID};
            // Create the cursor pointing to the SDCard
            Cursor cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
                    projection, // Which columns to return
                    null,       // Return all rows
                    null,       
                    null); 
            int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
            int size = cursor.getCount();
            // If size is 0, there are no images on the SD Card.
            if (size == 0) {
                //No Images available, post some message to the user
            }
            int imageID = 0;
            for (int i = 0; i < size; i++) {
                cursor.moveToPosition(i);
                imageID = cursor.getInt(columnIndex);
                uri = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID);
                try {
                    bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
                    if (bitmap != null) {
                        newBitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);
                        bitmap.recycle();
                        if (newBitmap != null) {
                            publishProgress(new LoadedImage(newBitmap));
                        }
                    }
                } catch (IOException e) {
                    //Error fetching image, try to recover
                }
            }
            cursor.close();
            return null;
        }
        /**
         * Add a new LoadedImage in the images grid.
         *
         * @param value The image.
         */
        @Override
        public void onProgressUpdate(LoadedImage... value) {
            addImage(value);
        }
        /**
         * Set the visibility of the progress bar to false.
         * 
         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
         */
        @Override
        protected void onPostExecute(Object result) {
            setProgressBarIndeterminateVisibility(false);
        }
    }

    /**
     * Adapter for our image files. 
     * 
     * @author Mihai Fonoage
     *
     */
    class ImageAdapter extends BaseAdapter {

        private Context mContext; 
        private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();

        public ImageAdapter(Context context) { 
            mContext = context; 
        } 

        public void addPhoto(LoadedImage photo) { 
            photos.add(photo); 
        } 

        public int getCount() { 
            return photos.size(); 
        } 

        public Object getItem(int position) { 
            return photos.get(position); 
        } 

        public long getItemId(int position) { 
            return position; 
        } 

        public View getView(int position, View convertView, ViewGroup parent) { 
            final ImageView imageView; 
            if (convertView == null) { 
                imageView = new ImageView(mContext); 
            } else { 
                imageView = (ImageView) convertView; 
            } 
            imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
            imageView.setPadding(8, 8, 8, 8);
            imageView.setImageBitmap(photos.get(position).getBitmap());
            return imageView; 
        } 
    }

    /**
     * A LoadedImage contains the Bitmap loaded for the image.
     */
    private static class LoadedImage {
        Bitmap mBitmap;

        LoadedImage(Bitmap bitmap) {
            mBitmap = bitmap;
        }

        public Bitmap getBitmap() {
            return mBitmap;
        }
    }
    /**
     * When an image is clicked, load that image as a puzzle. 
     */
    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {        
        int columnIndex = 0;
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
                projection,
                null, 
                null, 
                null);
        if (cursor != null) {
            columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToPosition(position);
            String imagePath = cursor.getString(columnIndex); 

            FileInputStream is = null;
            BufferedInputStream bis = null;
            try {
                is = new FileInputStream(new File(imagePath));
                bis = new BufferedInputStream(is);
                Bitmap bitmap = BitmapFactory.decodeStream(bis);
                Bitmap useThisBitmap = Bitmap.createScaledBitmap(bitmap, parent.getWidth(), parent.getHeight(), true);
                bitmap.recycle();
                //Display bitmap (useThisBitmap)
            } 
            catch (Exception e) {
                //Try to recover
            }
            finally {
                try {
                    if (bis != null) {
                        bis.close();
                    }
                    if (is != null) {
                        is.close();
                    }
                    cursor.close();
                    projection = null;
                } catch (Exception e) {
                }
            }
        }
    }

}

The sdcard.xml file:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    
    <GridView  
        android:id="@+id/sdcard"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp" 
        android:stretchMode="columnWidth"
        android:gravity="center" />
        
</FrameLayout>    

That's it. Let me know if you have any questions.

Enjoy!

221 comments:

«Oldest   ‹Older   201 – 221 of 221
Muhammad Imran said...

amazon expert consultant
Fulfillment by Amazon
Amazon Seller Consulting Agency
Amazon consulting firms

cyphershield said...

blockchain full node audit

Cyphershieldtech said...

ethereum smart contract audit

Cyphershieldtech said...

smart contract auditing services

blockchain development said...

Benefits of cryptocurrency exchange script
binance clone script V2.0 enhanced
Crypto Exchange Software
Cryptocurrency Exchange Script
binance clone Software
bitcoin Exchange Script
binance clone Script

Website Development Services Noida said...

we are the best Flutter App development company in noida

car dekhe said...

CarDekhen is India's leading car search venture that helps users buy cars that are right for them. The company has tie-ups with many auto manufacturers, more than 4000 car dealers and numerous financial institutions to facilitate the purchase of vehicles.

Blogging Articles said...

A concept car (also known as a concept vehicle, show vehicle or prototype) is a made to showcase new styling and/or new technology

car dekhen said...

CarDekhen is India's leading portal helping users buy & experience cars like never before. Explore us!

self drive car rental noida
self drive car rental greater noida

digital sanstha said...

I use this in my proj bt i have one problem i use onclicklistner in getview when user click on image it works only after all images get load bt i want it work when we adding images too so please help me thanks in advance..
car rental services in Delhi

cryptocurrency said...

Blockchain casino game Clone Script
Bitcoin harving 2024
crypto casino game development
NFT game development company
metaverse game development company
Bc.game clone script
crypto casino script
Stake alternative

Binance clone script said...

Ultimate way to create your crypto exchange like binance by Binance clone script

Blackjack game clone said...

Raise your casino card game like Black jack using BlackJack Game Clone Development

MNB Soft Solution Pvt Ltd said...

Thanks for sharing this kind of information. This is meant to me. Check the best mobile app development agency if you want the best mobile app solutions.

EMS Digital said...

Your blog is a captivating journey through insightful thoughts and eloquent expression. Each post is a testament to your profound understanding and passion for the subject matter. Your words resonate deeply, leaving readers both enlightened and inspired. Thank you for sharing your unique perspective and enriching the online community.

business consultant in uae

EMS Digital said...
This comment has been removed by the author.
EMS Digital said...

I cannot thank Arab Business Consultant enough for their invaluable guidance and support. Their unmatched expertise in navigating the complexities of the UAE Free Zone has been instrumental in driving our enterprise towards success.

James Cordon said...

Visit CMOLDS one of the web development companies in dubai offering complete and most authentic services in this domain.

Crypto trading bot development company said...

Your way of explaining things is awesome; it makes understanding easier. Your post provided me with a lot of useful information. If anyone wants to learn more about this crypto trading bot development, feel free to check out my page and share your thoughts.

Crypto arbitrage trading bot development company said...

Your post is truly amazing, and I've been searching for something like this for a while. Thank you so much! If anyone wants to build a crypto trading bot development, my blog and my Best crypto trading bot development company can help. Drop by and share your thoughts.

James Cordon said...

CMOLDS is a leading app development company uae providing complete and authentic services in this domain.

«Oldest ‹Older   201 – 221 of 221   Newer› Newest»