Browse through more Android tutorials. If you'd like to see a tutorial on any particular topic, do leave a comment in the wishlist page. We frequently post new tutorials along with app releases. You may subscribe to our newsletter to get all updates in your inbox.
Now you can get the latest Java source bundled with each app update. Install the app from Google Play and go to Settings > Extras.

«  Create Flappy Bird in Android Create a currency converter app  »

Build your first pro Android application with Eclipse

DownloadDownload

Keywords: AppCompat Fragment ActionBar ViewPager Navigation Drawer LoaderManager SQLiteDatabase CursorLoader SimpleCursorAdapter ContentProvider SQLiteOpenHelper ContentResolver ListFragment ListView GridView DialogFragment Volley Library RequestQueue ImageLoader NetworkImageView

Contents

6 « Prev Page

14. Content Provider

We'll create a SQLite database in our app and expose the data through ContentProvider. Content Provider is the means through which data is made accessible to the application. It is one of the components of Android and has to be declared in the manifest.
As usual, Eclipse provides a wizard for easily creating ContentProvider. Go to File > New > Other... and select Android Object under Android. Click Next and select Content Provider in next screen. Click Next and provide details as follows.
Class Name: DataProvider
URI Authorities: com.appsrox.showcase.provider
Uncheck Exported and click Finish.
The DataProvider class gets created along with a declaration in the manifest. Here is an excerpt from the manifest.
        <provider
            android:name="com.appsrox.showcase.DataProvider"
            android:authorities="com.appsrox.showcase.provider"
            android:enabled="true"
            android:exported="false" >
        </provider>
					

Exported option makes the Content Provider accessible to external applications.

Let's take a look at the DataProvider class. We've added a nested DbHelper class that gives access to the SQLite database.
	public class DataProvider extends ContentProvider {
	
		public static final String TABLE_DATA = "data";
		public static final String COL_ID = "_id";
		public static final String COL_CONTENT = "content";	
		
		private DbHelper dbHelper;
		
		public DataProvider() {
		}
		
		@Override
		public boolean onCreate() {
			dbHelper = new DbHelper(getContext());
			return true;
		}

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

		@Override
		public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
			throw new UnsupportedOperationException("Not yet implemented");
		}
		
		@Override
		public Uri insert(Uri uri, ContentValues values) {
			throw new UnsupportedOperationException("Not yet implemented");
		}	

		@Override
		public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
			throw new UnsupportedOperationException("Not yet implemented");
		}
		
		@Override
		public int delete(Uri uri, String selection, String[] selectionArgs) {
			throw new UnsupportedOperationException("Not yet implemented");
		}
		
		/**
		 * Helper class that actually creates and manages the provider's underlying data repository.
		 */
		protected static final class DbHelper extends SQLiteOpenHelper {
			
			private static final String DATABASE_NAME = "showcase.db";
			private static final int DATABASE_VERSION = 1;
			
			private static final String SQL_CREATE_DATA = "create table data (_id integer primary key autoincrement, content text);";		

			public DbHelper(Context context) {
				super(context, DATABASE_NAME, null, DATABASE_VERSION);
			}

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

			@Override
			public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			}
			
		}	
	}					
					
Android makes it easy to manage a SQLite database through SQLiteOpenHelper. It provides callbacks for creating and upgrading of database as well as methods for executing SQL queries.
We'll take help of DbHelper class to implement the overridden methods corresponding to each CRUD operation.
	public static final Uri CONTENT_URI_DATA = Uri.parse("content://com.appsrox.showcase.provider/data");
	
	private static final int DATA_ALLROWS = 1;
	private static final int DATA_SINGLE_ROW = 2;

	private static final UriMatcher uriMatcher;
	static {
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI("com.appsrox.showcase.provider", "data", DATA_ALLROWS);
		uriMatcher.addURI("com.appsrox.showcase.provider", "data/#", DATA_SINGLE_ROW);
	}
	
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		SQLiteDatabase db = dbHelper.getReadableDatabase();
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		
		switch(uriMatcher.match(uri)) {
		case DATA_ALLROWS:
			qb.setTables(TABLE_DATA);
			break;
			
		case DATA_SINGLE_ROW:
			qb.setTables(TABLE_DATA);
			qb.appendWhere("_id = " + uri.getLastPathSegment());
			break;			
			
		default:
			throw new IllegalArgumentException("Unsupported URI: " + uri);			
		}
		
		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}	

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
        
		long id;
		switch(uriMatcher.match(uri)) {
		case DATA_ALLROWS:
			id = db.insertOrThrow(TABLE_DATA, null, values);
			break;
			
		default:
			throw new IllegalArgumentException("Unsupported URI: " + uri);
		}
		
		Uri insertUri = ContentUris.withAppendedId(uri, id);
		getContext().getContentResolver().notifyChange(insertUri, null);
		return insertUri;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		int count;
		switch(uriMatcher.match(uri)) {
		case DATA_ALLROWS:
			count = db.update(TABLE_DATA, values, selection, selectionArgs);
			break;
			
		case DATA_SINGLE_ROW:
			count = db.update(TABLE_DATA, values, "_id = ?", new String[]{uri.getLastPathSegment()});
			break;
			
		default:
			throw new IllegalArgumentException("Unsupported URI: " + uri);			
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}	

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		int count;
		switch(uriMatcher.match(uri)) {
		case DATA_ALLROWS:
			count = db.delete(TABLE_DATA, selection, selectionArgs);
			break;
			
		case DATA_SINGLE_ROW:
			count = db.delete(TABLE_DATA, "_id = ?", new String[]{uri.getLastPathSegment()});
			break;
			
		default:
			throw new IllegalArgumentException("Unsupported URI: " + uri);			
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}					
					
The pattern in which we implement the methods is same i.e. use UriMatcher to match the Uri passed to the method and take action accordingly. Currently we support operations on a single row and on all rows of the table.
The code is self-explanatory. We get an instance of database through dbHelper and then call an appropriate method on db instance. However, do note the use of notifyChange() method to notify registered Content Observers.

15. Data model

We next create a simple POJO class that can be used as transfer object within the application.
	public class Data {
		
		public static final String TITLE = "title";
		public static final String DESCRIPTION = "description";
		public static final String ICON_URL = "icon_url";
		public static final String DOWNLOAD_URL = "download_url";
		public static final String TUTORIAL_URL = "tutorial_url";	

		private String title;
		private String description;
		private String icon;
		private String downloadUrl;
		private String tutorialUrl;
		
		public Data() {
			super();
		}

		public Data(String title, String description, String icon, String downloadUrl, String tutorialUrl) {
			super();
			this.title = title;
			this.description = description;
			this.icon = icon;
			this.downloadUrl = downloadUrl;
			this.tutorialUrl = tutorialUrl;
		}
		
		public Data(String jsonStr) {
			super();
			try {
				JSONObject json = new JSONObject(jsonStr);
				title = json.optString(TITLE);
				description = json.optString(DESCRIPTION);
				icon = json.optString(ICON_URL);
				downloadUrl = json.optString(DOWNLOAD_URL);
				tutorialUrl = json.optString(TUTORIAL_URL);
			} catch (JSONException e) {}
		}	

		public String getTitle() {
			return title;
		}
		public void setTitle(String title) {
			this.title = title;
		}

		public String getDescription() {
			return description;
		}
		public void setDescription(String description) {
			this.description = description;
		}

		public String getIcon() {
			return icon;
		}
		public void setIcon(String icon) {
			this.icon = icon;
		}

		public String getDownloadUrl() {
			return downloadUrl;
		}
		public void setDownloadUrl(String downloadUrl) {
			this.downloadUrl = downloadUrl;
		}

		public String getTutorialUrl() {
			return tutorialUrl;
		}
		public void setTutorialUrl(String tutorialUrl) {
			this.tutorialUrl = tutorialUrl;
		}

		@Override
		public String toString() {
			try {
				JSONObject json = new JSONObject();
				json.put(TITLE, title);
				json.put(DESCRIPTION, description);
				json.put(ICON_URL, icon);
				json.put(DOWNLOAD_URL, downloadUrl);
				json.put(TUTORIAL_URL, tutorialUrl);
				return json.toString();
			} catch (JSONException e) {}
			return "{}";
		}
		
	}
					
The interesting piece of code is the use of JSONObject to stringify the data. We'll use this class extensively in adapters for holding and displaying data.
Now that we have finished the ground work, we will next implement the fragments for displaying data in the main screen.
Share the love:  

Next Page » 6

App Gen
App Name:
Project Name:
Package:
Screens:
Splash
Login
Help
Main
List  Grid  Pager
Detail
Settings
Options:
Action Bar
Navigation Drawer
Dummy Data
Generate
Free Apps