Archive

Posts Tagged ‘custom’

A Custom Scrollable Image View


I grabbed it from AndroidHowto

package pete.android.study;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

public class ScrollImageView extends View {
	private final int DEFAULT_PADDING = 10;
	private Display mDisplay;
	private Bitmap mImage;

	/* Current x and y of the touch */
	private float mCurrentX = 0;
	private float mCurrentY = 0;

	private float mTotalX = 0;
	private float mTotalY = 0;
	/* The touch distance change from the current touch */
	private float mDeltaX = 0;
	private float mDeltaY = 0;

	int mDisplayWidth;
	int mDisplayHeight;
	int mPadding;

	public ScrollImageView(Context context) {
		super(context);
		initScrollImageView(context);
	}
	public ScrollImageView(Context context, AttributeSet attributeSet) {
		super(context);
		initScrollImageView(context);
	}
	private void initScrollImageView(Context context) {
		mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
		mPadding = DEFAULT_PADDING;
	}
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int width = measureDim(widthMeasureSpec, mDisplay.getWidth());
		int height = measureDim(heightMeasureSpec, mDisplay.getHeight());
		setMeasuredDimension(width, height);
	}
	private int measureDim(int measureSpec, int size) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = size;
            if (specMode == MeasureSpec.AT_MOST) {
               result = Math.min(result, specSize);
            }
        }
        return result;
    }
	public Bitmap getImage() {
		return mImage;
	}
	public void setImage(Bitmap image) {
		mImage = image;
	}

	public int getPadding() {
		return mPadding;
	}

	public void setPadding(int padding) {
		this.mPadding = padding;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
		mCurrentX = event.getRawX();
		mCurrentY = event.getRawY();
		}
		else if (event.getAction() == MotionEvent.ACTION_MOVE) {
		float x = event.getRawX();
		float y = event.getRawY();

		// Update how much the touch moved
		mDeltaX = x - mCurrentX;
		mDeltaY = y - mCurrentY;

		mCurrentX = x;
		mCurrentY = y;

		invalidate();
		}
		// Consume event
		return true;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mImage == null) {
			return;
		}

		float newTotalX = mTotalX + mDeltaX;
		// Don't scroll off the left or right edges of the bitmap.
		if (mPadding > newTotalX && newTotalX > getMeasuredWidth() - mImage.getWidth() - mPadding)
			mTotalX += mDeltaX;

		float newTotalY = mTotalY + mDeltaY;
		// Don't scroll off the top or bottom edges of the bitmap.
		if (mPadding > newTotalY && newTotalY > getMeasuredHeight() - mImage.getHeight() - mPadding)
			mTotalY += mDeltaY;
			Paint paint = new Paint();
			canvas.drawBitmap(mImage, mTotalX, mTotalY, paint);
		}
	}

Cheers,
Pete Houston

Create and use custom Content Provider

June 19, 2011 11 comments

In Android, when you have many applications and want to share data between them, you need to implement a content provider as recommended.

This is the syntax:

<standard-prefix>://<authority>/<paths>/<id>

As you have an Android device, you probably have some provided content provider, such as: Contacts, Browser, Settings, CallLog, MediaStore…

If you want to retrieve all contacts:

content://contacts/people

Get a specific contact:

content://contacts/people/3

Get all bookmarks from browser:
content://browser/bookmarks

That’s some common things, you should have known it.

However, you might need to create your own custom content provider to use as well, don’t you?

You might need to refer to this page before reading next part in my tutorials: Android Developers’ Page – Content Provider

Basically, you need to extend to ContentProvider class which provides some abstracts methods:

  • getType(): Returns the MIME type of the data at the given URI.
  • onCreate(): Called when the provider is being started.
  • query(): Receives a request from a client. The result is returned as a Cursor object.
  • insert(): Inserts a new record into the content provider.
  • delete(): Deletes an existing record from the content provider.
  • update(): Updates an existing record from the content provider

For data processing within your content provider, you may choose to store your data in any way you like: database, files, XML or web services. I use SQLite database in this tutorial.

Ok, so I will create a ContentProvider for something called Articles, using a database: “articles.db“, one table “tbl_articles” with three columns: “_id“, “title“, “content” for simplicity.

This is what you have upon starting:

public class ArticleProvider extends ContentProvider
{
   @Override
   public int delete(Uri uri, String where, String[] whereArgs) {
      return 0;
   }

   @Override
   public String getType(Uri uri) {
      return null;
   }

   @Override
   public Uri insert(Uri uri, ContentValues values) {
      return null;
   }

   @Override
   public boolean onCreate() {
      return false;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
         String[] selectionArgs, String sortOrder) {
      return null;
   }

   @Override
   public int update(Uri uri, ContentValues values, String where,
         String[] whereArgs) {
      return 0;
   }
}

Next is to create a helper class which provides such a way to access SQLite database and manipulate: ArticleDBHelper, will extend SQLiteOpenHelper.

	private static class ArticleDBHelper extends SQLiteOpenHelper {

		public ArticleDBHelper(Context c) {
			super(c, ArticleMetaData.DATABASE_NAME, null, ArticleMetaData.DATABSE_VERSION);
		}

		private static final String SQL_QUERY_CREATE =
			"CREATE TABLE " + ArticleMetaData.ArticleTable.TABLE_NAME + " (" +
			ArticleMetaData.ArticleTable.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
			ArticleMetaData.ArticleTable.TITLE + " TEXT NOT NULL, " +
			ArticleMetaData.ArticleTable.CONTENT + " TEXT NOT NULL" +
			");"
		;

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(SQL_QUERY_CREATE);
		}

		private static final String SQL_QUERY_DROP =
			"DROP TABLE IF EXISTS " + ArticleMetaData.ArticleTable.TABLE_NAME + ";"
		;

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer) {
			db.execSQL(SQL_QUERY_DROP);
			onCreate(db);
		}
	}

We need to provide some constants to use throughout program as well, which is written in a seperate class.

package pete.android.study.provider;

import android.net.Uri;
import android.provider.BaseColumns;

public class ArticleMetaData {
	private ArticleMetaData() { }

	public static final String AUTHORITY = "pete.android.study.provider.Articles";
	public static final Uri CONTENT_URI = Uri.parse(
		"content://" + AUTHORITY + "/articles"
	);

	public static final String DATABASE_NAME = "articles.db";
	public static final int DATABASE_VERSION = 1;

	public static final String CONTENT_TYPE_ARTICLES_LIST = "vnd.android.cursor.dir/vnd.pete.articles";
	public static final String CONTENT_TYPE_ARTICLE_ONE = "vnd.android.cursor.item/vnd.pete.articles";

	public class ArticleTable implements BaseColumns {
		private ArticleTable() { }

		public static final String TABLE_NAME = "tbl_articles";

		public static final String ID = "_id";
		public static final String TITLE = "title";
		public static final String CONTENT = "content";
	}

}

ArticleMetaData class defines some required constant values to use:

+ AUTHORITY: this is the name of your content provider

+ CONTENT_URI: is your content provider URI for other applications to access data from it.

Let’s say if you want to get all articles, it would be like:

content://pete.android.study.provider.Articles/articles

To retrieve a specific article:

content://pete.android.study.provider.Articles/articles/13

+ CONTENT_TYPE_ARTICLES_LIST, CONTENT_TYPE_ARTICLE_ONE: simply define what kind of MIME value return.

Syntax:

for a list: vnd.android.cursor.dir/vnd.your-domain.your-item-name

for one item: vnd.android.cursor.item/vnd.your-domain.your-your-item-name

The object of UriMatcher will parse the input content URI to define which kind of MIME used to process. So when you need to return both list and single item, you need to define those two of CONTENT_TYPE.

Here the fully implementation:

package pete.android.study.provider;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class ArticleProvider extends ContentProvider {

	private static final UriMatcher sUriMatcher;
	private static final int ARTICLE_TYPE_LIST = 1;
	private static final int ARTICLE_TYPE_ONE = 2;
	static {
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		sUriMatcher.addURI(ArticleMetaData.AUTHORITY, "articles", ARTICLE_TYPE_LIST);
		sUriMatcher.addURI(ArticleMetaData.AUTHORITY, "articles/#", ARTICLE_TYPE_ONE);
	}

	private static final HashMap<String, String> sArticlesProjectionMap;
	static {
		sArticlesProjectionMap = new HashMap<String, String>();
		sArticlesProjectionMap.put(ArticleMetaData.ArticleTable.ID, ArticleMetaData.ArticleTable.ID);
		sArticlesProjectionMap.put(ArticleMetaData.ArticleTable.TITLE, ArticleMetaData.ArticleTable.TITLE);
		sArticlesProjectionMap.put(ArticleMetaData.ArticleTable.CONTENT, ArticleMetaData.ArticleTable.CONTENT);
	}

	private static class ArticleDBHelper extends SQLiteOpenHelper {

		public ArticleDBHelper(Context c) {
			super(c, ArticleMetaData.DATABASE_NAME, null, ArticleMetaData.DATABSE_VERSION);
		}

		private static final String SQL_QUERY_CREATE =
			"CREATE TABLE " + ArticleMetaData.ArticleTable.TABLE_NAME + " (" +
			ArticleMetaData.ArticleTable.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
			ArticleMetaData.ArticleTable.TITLE + " TEXT NOT NULL, " +
			ArticleMetaData.ArticleTable.CONTENT + " TEXT NOT NULL" +
			");"
		;

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(SQL_QUERY_CREATE);
		}

		private static final String SQL_QUERY_DROP =
			"DROP TABLE IF EXISTS " + ArticleMetaData.ArticleTable.TABLE_NAME + ";"
		;

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer) {
			db.execSQL(SQL_QUERY_DROP);
			onCreate(db);
		}
	}

	private ArticleDBHelper mDbHelper;

	@Override
	public boolean onCreate() {
		mDbHelper = new ArticleDBHelper(getContext());
		return false;
	}

	@Override
	public int delete(Uri uri, String where, String[] whereArgs) {
		SQLiteDatabase db = mDbHelper.getWritableDatabase();
		int count = 0;
		switch(sUriMatcher.match(uri)) {
			case ARTICLE_TYPE_LIST:
				count = db.delete(ArticleMetaData.ArticleTable.TABLE_NAME, where, whereArgs);
				break;

			case ARTICLE_TYPE_ONE:
				String rowId = uri.getPathSegments().get(1);
				count = db.delete(ArticleMetaData.ArticleTable.TABLE_NAME,
					ArticleMetaData.ArticleTable.ID + " = " + rowId +
						(!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""),
					whereArgs);
				break;

			default:
				throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri) {

		switch(sUriMatcher.match(uri)) {
			case ARTICLE_TYPE_LIST:
				return ArticleMetaData.CONTENT_TYPE_ARTICLES_LIST;

			case ARTICLE_TYPE_ONE:
				return ArticleMetaData.CONTENT_TYPE_ARTICLE_ONE;

			default:
				throw new IllegalArgumentException("Unknown URI: " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {

		if(sUriMatcher.match(uri) != ARTICLE_TYPE_LIST) {
			throw new IllegalArgumentException("[Insert](01)Unknown URI: " + uri);
		}

		SQLiteDatabase db = mDbHelper.getWritableDatabase();
		long rowId = db.insert(ArticleMetaData.ArticleTable.TABLE_NAME, null, values);
		if(rowId > 0) {
			Uri articleUri = ContentUris.withAppendedId(ArticleMetaData.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(articleUri, null);
			return articleUri;
		}
		throw new IllegalArgumentException("[Insert](02)Unknown URI: " + uri);
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
		switch(sUriMatcher.match(uri)) {
			case ARTICLE_TYPE_LIST:
				builder.setTables(ArticleMetaData.ArticleTable.TABLE_NAME);
				builder.setProjectionMap(sArticlesProjectionMap);
				break;

			case ARTICLE_TYPE_ONE:
				builder.setTables(ArticleMetaData.ArticleTable.TABLE_NAME);
				builder.setProjectionMap(sArticlesProjectionMap);
				builder.appendWhere(ArticleMetaData.ArticleTable.ID + " = " +
						uri.getPathSegments().get(1));
				break;

			default:
				throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		SQLiteDatabase db = mDbHelper.getReadableDatabase();
		Cursor queryCursor = builder.query(db, projection, selection, selectionArgs, null, null, null);
		queryCursor.setNotificationUri(getContext().getContentResolver(), uri);

		return queryCursor;
	}

	@Override
	public int update(Uri uri, ContentValues values, String where,
			String[] whereArgs) {

		SQLiteDatabase db = mDbHelper.getWritableDatabase();
		int count = 0;
		switch(sUriMatcher.match(uri)) {
			case ARTICLE_TYPE_LIST:
				count = db.update(ArticleMetaData.ArticleTable.TABLE_NAME, values, where, whereArgs);
				break;

			case ARTICLE_TYPE_ONE:
				String rowId = uri.getPathSegments().get(1);
				count = db.update(ArticleMetaData.ArticleTable.TABLE_NAME, values,
					ArticleMetaData.ArticleTable.ID + " = " + rowId +
						(!TextUtils.isEmpty(where) ? " AND (" + ")" : ""),
				whereArgs);

			default:
				throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

}

When you insert/update/delete, always remember to call “notifyChange()” to the URI that has been used.

When you query values, always remember to to call “setNotificationUri()” for Cursor.

That’s done for creating your custom content provider. In order to use, you need to register it to AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="pete.android.study"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

		<provider android:name="pete.android.study.provider.ArticleProvider"
			android:authorities="pete.android.study.provider.Articles">
		</provider>
    </application>
</manifest>

android:name = the class name that handling content provider
android:authorities = the authority name you define

You’ve done creating your own custom Content Provider 🙂

Get my sample project for custom Content Provider: Sample Project

 

Cheers,

Pete Houston

 

Custom grid view of applications

June 12, 2011 24 comments

Today, I’ll guide you how to create a simple grid view that displays the list of applications, look at screenshot below:

Application Grid Screenshot

Application Grid Screenshot

Similar to ListView, the GridView is the view control that displays its items like a grid, so you just need to work around similar to the PhoneBook ListView in my previous post.

A – Create the Project

Project Name: Application Grid

Application Name: Application Grid

Build Target: Android 2.3.3

Package Name: pete.android.study

Create Activity: MainActivity

Min SDK: 10

B – Sketch the Layout

Like the list view, we all need to construct 2 layout:

+ one layout for each item inside the grid

+ one layout for the main grid view display

1. Grid Item Layout

Very simple, we create one image view to display application icon and one text view to display application name.

Put this file: layout_appinfo.xml into /res/layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center_horizontal"
  >

  <ImageView
      android:id="@+id/ivIcon"
      android:layout_width="48dip"
      android:layout_height="48dip"
      android:scaleType="centerCrop"
  />
  <TextView
  	  android:id="@+id/tvName"
  	  android:layout_width="72dip"
  	  android:layout_height="wrap_content"
  	  android:gravity="center"
  	  android:textStyle="bold"
  />

</LinearLayout>

Remember to set image view “android:scaleType=”centerCrop”” to make image bitmap fit into the box. Also, set text alignment to “center” to make it display nicely with top icon.

2. Main Layout

Just put a grid view inside. Put this file main.xml into /res/layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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/gvMain"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:numColumns="4"
		android:columnWidth="72dip"
		android:gravity="center"
		android:stretchMode="columnWidth"
		android:padding="10dip"
		android:verticalSpacing="10dip"
		android:horizontalSpacing="10dip"
	/>

</LinearLayout>

C – Class Design: On the Idea

Application Grid: Class Diagram

Application Grid: Class Diagram

D – From Design to Coding

1. AppInfo: (AppInfo.java)  the entity class which holds information of application including: application icon and application name.

package pete.android.study;

import android.graphics.Bitmap;

public class AppInfo {
	private Bitmap mIcon;
	private String mName;

	public AppInfo(Bitmap icon, String name) {
		mIcon = icon;
		mName = name;
	}

	public void setIcon(Bitmap icon) {
		mIcon = icon;
	}
	public Bitmap getIcon() {
		return mIcon;
	}

	public void setName(String name) {
		mName = name;
	}
	public String getName() {
		return mName;
	}

}

2. AppInfoAdapter: (AppInfoAdapter.java) the adapter to handle the list of application info in the grid view.

package pete.android.study;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class AppInfoAdapter extends BaseAdapter {
	private Context mContext;
	private List<AppInfo> mListAppInfo;

	public AppInfoAdapter(Context context, List<AppInfo> list) {
		mContext = context;
		mListAppInfo = list;
	}

	@Override
	public int getCount() {
		return mListAppInfo.size();
	}

	@Override
	public Object getItem(int position) {
		return mListAppInfo.get(position);
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		AppInfo entry = mListAppInfo.get(position);

		if(convertView == null) {
			LayoutInflater inflater = LayoutInflater.from(mContext);
			convertView = inflater.inflate(R.layout.layout_appinfo, null);
		}

		ImageView ivIcon = (ImageView)convertView.findViewById(R.id.ivIcon);
		ivIcon.setImageBitmap(entry.getIcon());

		TextView tvName = (TextView)convertView.findViewById(R.id.tvName);
		tvName.setText(entry.getName());

		return convertView;
	}
}

3. MainActivity: (MainActivity.java) the entry point to the application

package pete.android.study;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.GridView;

public class MainActivity extends Activity {

	private GridView mGridMain;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mGridMain = (GridView)findViewById(R.id.gvMain);
        Resources res = getResources();
        List<AppInfo> listAppInfo = new ArrayList<AppInfo>();
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_browser), "Internet"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_clock), "Clock"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_display), "Display"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_favorite), "Favorite"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_home), "Home"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_mail), "Mail"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_media), "Media"));
        mGridMain.setAdapter(new AppInfoAdapter(this, listAppInfo));

    }
}

E – Note

– For the layout of each item in the grid view, if the LinearLayout you don’t set “android:gravity=”center_horizontal”“, then it will display very ugly.

– Make sure you put your application bitmap into /drawble

– Try to practice with this kind of simple application to understand the idea of Adapter in GridView, and ListView in my previous post.

– Think about design when u’re good at coding.

F – Get the Sample Project by Pete

Pick your favorite server: Mediafire | Rapidshare | FreeFileHosting | Megaupload

G – Final Words

– Have you learned something?

– Hope you enjoy it!

– Feel free to ask, comment, and suggest below; you’re all welcomed!

H – Update on Request

1. Alfox on request to add extra click event for GridView

– Since this is a GridView so we need to implement AdapterView.OnItemClickListener, and it must be set to GridView object, and not in the Adapter. This is a common mistake when people try to implement ClickListener on the Adapter!

– Here I will add this listener to add functionality that a Toast is displayed with the item name when users click on an item of GridView. It requires some changes for above source code, like below:

(1) Update the AppInfoAdapter class (AppInfoAdapter.java) to have a ViewHolder pattern which will cache data.

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		AppInfo entry = mListAppInfo.get(position);
		ViewHolder holder = null;

		if(convertView == null) {
			LayoutInflater inflater = LayoutInflater.from(mContext);
			convertView = inflater.inflate(R.layout.layout_appinfo, null);
			holder = new ViewHolder();
			holder.ivIcon = (ImageView)convertView.findViewById(R.id.ivIcon);
			holder.tvName = (TextView)convertView.findViewById(R.id.tvName);
			convertView.setTag(holder);
		}
		else {
			holder = (ViewHolder)convertView.getTag();
		}

		holder.ivIcon.setImageBitmap(entry.getIcon());
		holder.tvName.setText(entry.getName());

		return convertView;
	}

	static class ViewHolder {
		ImageView ivIcon;
		TextView tvName;
	}

(2) Add listener to the GridView and implement the listener to display information to Toast view.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mGridMain = (GridView)findViewById(R.id.gvMain);
        Resources res = getResources();
        List<AppInfo> listAppInfo = new ArrayList<AppInfo>();
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_browser), "Internet"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_clock), "Clock"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_display), "Display"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_favorite), "Favorite"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_home), "Home"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_mail), "Mail"));
        listAppInfo.add(new AppInfo(BitmapFactory.decodeResource(res, R.drawable.app_media), "Media"));
        mGridMain.setAdapter(new AppInfoAdapter(this, listAppInfo));

        mGridMain.setOnItemClickListener(mItemClickListener); // add a ItemClickListener

    }
    // our handle for listener
    private OnItemClickListener mItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
			ViewHolder holder = (ViewHolder)view.getTag();
			if(holder == null) {
				return;
			}
			Toast.makeText(MainActivity.this, "You have clicked on item '" + holder.tvName.getText() + "'", Toast.LENGTH_SHORT).show();
		}
	};

(3) Rebuild and run your application…free to click on GridView item to see how it works!!!

 

Hope you enjoy it!

Cheers,

Pete Houston