Android custom image gallery with checkbox in grid to select multiple


Some times we may require to select multiple images from gallery. So using the following method you will be able to select multiple images. Additionally it will also remove gallery app dependency.

It may not be sufficient method as I need to maintain two array in this activity, but it could vary on requirements. Please comment if you have any suggestion in code.

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" android:layout_height="fill_parent">
	<Button android:id="@+id/selectBtn"
		android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:text="Select" android:layout_alignParentBottom="true"
		android:layout_centerHorizontal="true"
		android:minWidth="200px" />
	<GridView android:id="@+id/PhoneImageGrid"
		android:layout_width="fill_parent" android:layout_height="fill_parent"
		android:numColumns="auto_fit" android:verticalSpacing="10dp"
		android:horizontalSpacing="10dp" android:columnWidth="90dp"
		android:stretchMode="columnWidth" android:gravity="center"
		android:layout_above="@id/selectBtn" />
</RelativeLayout>

galleryitem.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" android:layout_height="fill_parent">
	<ImageView android:id="@+id/thumbImage" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:layout_centerInParent="true" />
	<CheckBox android:id="@+id/itemCheckBox" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:layout_alignParentRight="true"
		android:layout_alignParentTop="true" />
</RelativeLayout>

AndroidCustomGalleryActivity.java

package com.isummation.customgallery;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidCustomGalleryActivity extends Activity {
	private int count;
	private Bitmap[] thumbnails;
	private boolean[] thumbnailsselection;
	private String[] arrPath;
	private ImageAdapter imageAdapter;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID };
		final String orderBy = MediaStore.Images.Media._ID;
		Cursor imagecursor = managedQuery(
				MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
				null, orderBy);
		int image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
		this.count = imagecursor.getCount();
		this.thumbnails = new Bitmap[this.count];
		this.arrPath = new String[this.count];
		this.thumbnailsselection = new boolean[this.count];
		for (int i = 0; i < this.count; i++) {
			imagecursor.moveToPosition(i);
			int id = imagecursor.getInt(image_column_index);
			int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
			thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail(
					getApplicationContext().getContentResolver(), id,
					MediaStore.Images.Thumbnails.MICRO_KIND, null);
			arrPath[i]= imagecursor.getString(dataColumnIndex);
		}
		GridView imagegrid = (GridView) findViewById(R.id.PhoneImageGrid);
		imageAdapter = new ImageAdapter();
		imagegrid.setAdapter(imageAdapter);
		imagecursor.close();

		final Button selectBtn = (Button) findViewById(R.id.selectBtn);
		selectBtn.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub
				final int len = thumbnailsselection.length;
				int cnt = 0;
				String selectImages = "";
				for (int i =0; i<len; i++)
				{
					if (thumbnailsselection[i]){
						cnt++;
						selectImages = selectImages + arrPath[i] + "|";
					}
				}
				if (cnt == 0){
					Toast.makeText(getApplicationContext(),
							"Please select at least one image",
							Toast.LENGTH_LONG).show();
				} else {
					Toast.makeText(getApplicationContext(),
							"You've selected Total " + cnt + " image(s).",
							Toast.LENGTH_LONG).show();
					Log.d("SelectedImages", selectImages);
				}
			}
		});
	}

	public class ImageAdapter extends BaseAdapter {
		private LayoutInflater mInflater;

		public ImageAdapter() {
			mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		public int getCount() {
			return count;
		}

		public Object getItem(int position) {
			return position;
		}

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

		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				holder = new ViewHolder();
				convertView = mInflater.inflate(
						R.layout.galleryitem, null);
				holder.imageview = (ImageView) convertView.findViewById(R.id.thumbImage);
				holder.checkbox = (CheckBox) convertView.findViewById(R.id.itemCheckBox);

				convertView.setTag(holder);
			}
			else {
				holder = (ViewHolder) convertView.getTag();
			}
			holder.checkbox.setId(position);
			holder.imageview.setId(position);
			holder.checkbox.setOnClickListener(new OnClickListener() {

				public void onClick(View v) {
					// TODO Auto-generated method stub
					CheckBox cb = (CheckBox) v;
					int id = cb.getId();
					if (thumbnailsselection[id]){
						cb.setChecked(false);
						thumbnailsselection[id] = false;
					} else {
						cb.setChecked(true);
						thumbnailsselection[id] = true;
					}
				}
			});
			holder.imageview.setOnClickListener(new OnClickListener() {

				public void onClick(View v) {
					// TODO Auto-generated method stub
					int id = v.getId();
					Intent intent = new Intent();
					intent.setAction(Intent.ACTION_VIEW);
					intent.setDataAndType(Uri.parse("file://" + arrPath[id]), "image/*");
					startActivity(intent);
				}
			});
			holder.imageview.setImageBitmap(thumbnails[position]);
			holder.checkbox.setChecked(thumbnailsselection[position]);
			holder.id = position;
			return convertView;
		}
	}
	class ViewHolder {
		ImageView imageview;
		CheckBox checkbox;
		int id;
	}
}

Download full source code:
Download

Update: need more features? see my open source project
Update: Please remove code that closes cursor. As this will not work in Android 4.0 and newer.

https://vikaskanani.wordpress.com/android-custom-gallery-and-instant-upload-project/

 

 

 

 

Advertisements

110 thoughts on “Android custom image gallery with checkbox in grid to select multiple

  1. Really great work, I am really impressed with the Idea that you have implemented to select multiple images through check box.

    Please post the “galleryitem.xml” layout which you forgot to add here.

      1. Android custom image gallery with checkbox in grid to select multiple solve my problem when run androig application message alrt unfortunately androidcustomgallery has stopped

        plz solve this problem

    1. Hi thanks for this sample code. I used this in my application. Now i have string which contain path of selected images. I want to upload those images to server using multipart format. But when i give it string path it shows me file not found exception. But when i put those images in gallery view i have them in it.

      Please suggest me solution.

  2. Nice job.btw,I want to add a select all button
    for(int i=0;i<thumbnails.length;i++){
    thumbnailsselection[i] = true;
    }

    photoGrid.invalidate();
    but it does not work.

  3. Just what i was looking for thanks.
    I just got this partially working in a android.widget.Gallery.
    Only the ImageView and ChecBox are beside each other
    not overlaying. Any ide how to fix that?

  4. Hi ! Great work ! Impressive !

    Btw, do you know how I could get selected image from another activity ? I would like to let user select photos, and use it later in my app. Singleton could be possibly able to do that, but if you have better ideas, I’m listening ;).

    Thx !

  5. A few suggestions:

    1. Use a HashSet to store file paths
    2. Remove the need for a boolean[] by storing the file path in each CheckBox as a Tag object
    3. I retrieve the file path from the checkbox when they are selected and store them in the HashSet. Likewise, I remove the file paths when they are deselected. These ops are done in the OnClickListener.
    4. Instead of keeping a counter and looping through the String[] storing file paths, I know just do a HashSet.isEmpty() to see if there are any photos selected
    5. If there are photos, I simply do a foreach loop on the HashSet to obtain them
    6. Instead of a new OnClickListener for each CheckBox, I only create one instance to be shared across all of them

    note: using checkbox.getId() for array indexes isn’t working for me as they are a very large number and I get a ArrayOutOfBoundsException when using your codes

  6. hey ,
    thanx for the nioce post…. just one problem , using it on a device for the first time crashes the app which i think is because the thumbnails are not already generated …. maybe ….. because when the app is run again it works like a charm … any idea whats the problem here\??

  7. hi vikas,
    thank you very much for your code ,this is what i’m looking for ,this code is really helped me.

    Regards,
    vigneshwaran

    1. Hey ! I wanted to know if i can select exactly 4 images using the code as u’ve given?
      I mean, if i select more than 4,the select button shud get disabled…
      Where shud i add the code for this?
      really in need of this ….
      Thanks !

  8. I am in 2.3 and have over 200 image in my photo gallery, I do see performance issue waiting for 1st screen…..Any idea to make the screen come out fast?

  9. Hi, Vikas. Thanks for this post. Instead of querying images from device’s gallery, is it possible to query images from built-in wallpaper’s gallery?

    1. Hi,

      You can use this code to browse gallery:

      Intent intent = new Intent();
      intent.setType(“image/*”);
      intent.setAction(Intent.ACTION_GET_CONTENT);
      startActivityForResult(
      Intent.createChooser(intent, “Select Picture”),
      PICK_IMAGE);

      And on Activity result, you can get the image from this code:

      Uri selectedImageUri = data.getData();

      Hope that helps.

  10. Sorry.. One error is occurred for me. Please give solution. The error is
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.isummation.customgallery/com.isummation.customgallery.AndroidCustomGalleryActivity}: java.lang.NullPointerException

  11. really wel…
    I need to change the selected images randomly on desktop..how can i do this work plz reply me…

  12. this in code i am unable to go back to thumbnail part after viewing the single selected image in full screen will please help me as soon as possible please

  13. Hello.
    If I use this custom gallery in a phone with few photos, it’s working, but if I use this in a phone with 200 photo for example, the app freeze.
    A possible solution for this?

    Thank you!

    1. It is because your phone may not keep thumbnails, so every time it regenerates thumbnails, which took time. Issue can be solved by putting loading dialog, and read 20/30 images at a time, then dynamically load others.

  14. Hi. I’m using your gallery. And it works nice, but when i select images with a significative weight then the gallery crashes. Why? Thanks in advance.

  15. Dear Vikas

    If possible please can you please upload the full source code to another site. The present site requires sign up which I don’t want to do.

  16. Vikas,

    could you attach some license and copyright to this code? I’d like to use it but the company lawyers are not happy until there is something legalese attached… 🙂

    Thanks,
    Gabriel

  17. Great work, Vikas!

    Any ideas on how to improve the performance?

    In a device with 568 images, it takes a looooong time to load all the thumbs and put them into the grid. 😦

    Thanks in advance,
    – Fernando

    1. Hi did you solve this problem of loading too many images.
      Can I start this on async task to reduce the load on main UI thread?

  18. How do I delete and image adn checkbox when checkbox selection is made. I can easily delete the image, not the checkbox until i exit the activity and come back.

  19. Please tell me how do i can display selected images in imageview? I can show only single image but i want to show multiple images.

  20. (Uri.parse(“file://” + arrPath[id]), “image.jpg”); in this how i set file path coz its not working so plz give me suggestion

  21. Hi Vikas,

    Great example…This is exactly I was looking for 🙂

    However, while using this example in v4.1, I frequently get couple of errors while forming the Custom Gallery of around 500 images
    1)android.data.staledataexception—it says I am trying to access cursor even after closing it.. As you mentioned, I am not closing the cursor..I have removed this line imgcursor.close() from the above example..but sometimes I still get this error 😦
    2)java.lang.OutOfMemmoryError—-this error occurs while getting the thumbnail of the image

    Can you pls help share some knowledge about the two errors and how to overcome this issues?

    Thanks,
    VijayRaj

  22. There is a problem with the gallery when larger thumbnails (MINI_KIND) or many pictures are displayed: it wastes a lot of memory. The solution is to remove the thumbnail loading from the main activity, only storing the paths and IDs. The actual loading of the bitmap thumbnail should only come in getView().

      1. Here’s what I did. Remove the Bitmap from the ImageItem:
        class ImageItem {
        boolean selection;
        int id;
        //Bitmap img;
        }
        Fix all resulting errors.

        Modify the end of getView (where you setup the holder) to the following:
        Bitmap thumbnail = MediaStore.Images.Thumbnails.getThumbnail(getApplicationContext().getContentResolver(), item.id, MediaStore.Images.Thumbnails.MICRO_KIND, null);
        holder.imageview.setImageBitmap(thumbnail);
        holder.checkbox.setChecked(item.selection);

        return convertView;

    1. I have good use of Vikas class, but i have to agree with previous comment, i tried the tip – I am now loading images one-by-one in getView and it is seems much faster than loading everything in onCreate.

    2. Thanks, I was just looking into that. Lazy loading is a must here. But, take note that loading from the SD card will create noticeable delays proportional to the number of images on the SD card. This is a physics problem. It would be hard if not impossible to program your way around it considering the resource limitations on mobile devices.

  23. hi

    im unable to see images and check boxes when i run your source code .can u please guide me what is required to make this code functional on my machine ?

  24. Hey really that is an impressive one..
    Thanx a lot Vikas..
    One more thing.. How can I copy all the selected images to a folder..??
    Can you please help me with this..

  25. hey..thats really an impressive one..
    thanx a lot Vikas..
    One more thing.. how can i copy the images selected to a folder in sdcard..??
    Please help me with thiss…

    1. your code helped me so much…. thanks but i need more help…. i want to hide selected images when click on checkbox…… pls rply early as soon as possible… thanks in andvnace

  26. I have an error in this line even i download this project and import it. Can u please heip me to come out of this error.
    image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);

  27. thanx for this needy example…bt i hv got a problem that is my vars. arrpath and thumbnails and not being recognised in imageadapter class so the gridview is not displayed..how to solve it please help me…ASAP

  28. Thanks for your very good code.
    I have a question for you.
    Can I use part of the sources at my contest application?

  29. i think the code could be better this way:
    toggle the state from selectable to not selectable.
    and this coulbe done with
    flag = false;
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
    super.bindView(view, context, cursor);
    view.setTag();
    CheckBox ckbox= (CheckBox) view.findViewById(R.id.itemCheckBox);
    if (flag) {
    ckbox.setVisibility(View.VISIBLE);
    }
    else
    ckbox.setVisibility(View.GONE);

    this way you can switch from multiselect mode to another mode, in which you can do more..
    anyway, its a flawless and great code! thanks for sharing

  30. Thanks vikas ….very good code its very useful for me….
    i have one question please solve this…
    when i choose multiple images and click on button at that time all selected images are pass and show in another activity.
    how can i do,,??
    give me any idea for do that.
    thanks in advance…

  31. Hello Vikas, thank you for the code. I was trying to use the same code for Videos as well, but while loading the Thumbnails I do not get a “Play” button view on the Thumbnail as we get in default gallery view.
    Is it possible to get the Thumbnail with Play button view over it? If so please suggest what can be done. Thanks in advance.

  32. Hello Vikas,

    I want to check and uncheck the checkbox by clicking the imageview. What should I do?

    I have tried this, but not working…

    holder.imageview.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
    int id = v.getId();
    CheckBox cb = (CheckBox) v;
    if (thumbnailsselection[id]){
    cb.setChecked(false);
    thumbnailsselection[id] = false;
    } else {
    cb.setChecked(true);
    thumbnailsselection[id] = true;
    }
    }
    });

    Getting this error..

    java.lang.ClassCastException; android.widget.ImageView cannot be cast to android.widget.CheckBox

    How to cast the checkbox from imageview? Is there any other options?

  33. hy can someone pls tell me how can i show folders that contains only images then on click of folders i will show all images inside that folder how can i show them then there should be multiple selection of images inside folder

    1. 1) Use mediastore query to retrieve all images
      contextResolver = context.getContentResolver();
      Cursor cursor = contextResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
      null, null, null, null);
      2) Store that image’s parent in an arrayList
      use imageFile=File(String path);
      and put imageFile.getParentFile().getName() in arrayList.
      before putting the parent directoryname you need to check if it already exist 😛

      3) Now u know all directories *Which contains images*

      That’s a kickstart for you…
      any suggestions are welcomed 🙂
      i have done it in my app ( https://play.google.com/store/apps/details?id=net.betterlabs.android.picbackman )

  34. actually am a beginner..i try to do a process…
    *if i select one image from /sdcard/particularfolder/(images are arranged in gridView),it will be viewed as full size in a next layout.imageview.i did some what related but it goes into the gallery when i select a image in grid view and show all the images in the sdcard,then i select any one there it shown in a imageview*

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s