Build your first pro Android application with Eclipse
DownloadKeywords: AppCompat Fragment ActionBar ViewPager Navigation Drawer LoaderManager SQLiteDatabase CursorLoader SimpleCursorAdapter ContentProvider SQLiteOpenHelper ContentResolver ListFragment ListView GridView DialogFragment Volley Library RequestQueue ImageLoader NetworkImageView
Contents- Overview
- Create a new Eclipse Android project
- Add Android Support library
- Android manifest
- Application theme
- Application class
- Splash screen
- Login screen
- Help screen
- Settings screen
- Navigation Drawer
- Main screen
- Dialog Fragment
- Content Provider
- Data model
- List Fragment
- Data Adapter
- Grid View
- View Pager
- Detail screen
- Volley Library
- What's next?
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.