Android Content Provider
Welcome to this post.
In this post we are going we learn about Content Provider.
In the previous post
, we work with the database. We learn how to create a database. How to use contract class. But we don't write any methods to access the database.
In this post, we learn about how to access the database. For access database, we use the content provider.
Let's start-
Before the start, we need contact class. please take a look
First, create a class and extend Content provider. In this case, my class name is DataProvider
1.query
2.insert
3.update
4.delete
5.getType
and Oncreate
let's do this one by one
OnCreate-
Now we have to add two variable to chek what type of data requested. If the value is 100 then requested full table data or if value match with 101 then it's requested for a single row data.
Let's add
1.First, we create an SQLiteDatabase through mHelper and database type must be written able database.Because we insert data into the database.
2.create an integer variable and initialize it by calling sUriMatcher.match(uri) and pass uri.
3.Now create a new Uri and this uri will be returned through this methods
4.now create a switch statement on the basis of match(int variable)
5.if case is 100 we insert data
6. inserted result is will be saved in a long variable
7. If the long variable is greater that zero the data inserted successfully and we also created a URI in this condition.
8.After that, we set a notification that's data is changed. Now see the code-
2.create an integer variable and initialize it by calling sUriMatcher.match(uri) and pass uri.
3.Now create a new Cursor and this cursor will be returned through this method
4.now create a switch statement on the basis of match(int variable)
5. I f case is 100, then we have to provide all data in the table. or If the case will be 101, we have to provide a single row data
6. query result is will be saved in a cursor
7. If the cursor is not null we have to set Notification uri
See the code-
In this post we are going we learn about Content Provider.
Content Provider |
In the previous post
, we work with the database. We learn how to create a database. How to use contract class. But we don't write any methods to access the database.
In this post, we learn about how to access the database. For access database, we use the content provider.
Let's start-
Before the start, we need contact class. please take a look
First, create a class and extend Content provider. In this case, my class name is DataProvider
public class DataProvider extends ContentProvider { }Now we have to override some methods.
1.query
2.insert
3.update
4.delete
5.getType
and Oncreate
let's do this one by one
OnCreate-
@Override public boolean onCreate() { return false; }Query-
@Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { return null; }Insert-
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { return null; }Update-
@Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; }Delete-
@Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; }getType-
@Nullable @Override public String getType(@NonNull Uri uri) { return null; }
Now we have to add two variable to chek what type of data requested. If the value is 100 then requested full table data or if value match with 101 then it's requested for a single row data.
Let's add
//use to get all data from this path private static final int TASKS = 100; //use to get single data from a single row private static final int TASK_WITH_ID = 101;Now we add a matcher to match with URI and also we add a method to match- method-
private static UriMatcher buildUriMatcher() { // Initialize a UriMatcher with no matches by passing in NO_MATCH to the constructor UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); /* *All paths added to the UriMatcher have a corresponding int. For each kind of uri you may want to access, add the corresponding match with addURI. The two calls below add matches for the task directory and a single item by ID.
if you are using string then use * insted of # */ matcher.addURI(DB_Contract.AUTHORITY,DB_Contract.PATH_TASKS,TASKS); matcher.addURI(DB_Contract.AUTHORITY,DB_Contract.PATH_TASKS + "/#",TASK_WITH_ID); return matcher; }now add a UriMatcher variable and initialize it through calling builUriMatcher():
//match with which uri private static final UriMatcher sUriMatcher = buildUriMatcher();add another instance to access variables-
private DatabaseHelper mHelper;
initialize it on Oncreate methods-@Override public boolean onCreate() { //create db instance mHelper = new DatabaseHelper(getContext()); return true; }Now we have a database. Time to write insert method for data-
1.First, we create an SQLiteDatabase through mHelper and database type must be written able database.Because we insert data into the database.
2.create an integer variable and initialize it by calling sUriMatcher.match(uri) and pass uri.
3.Now create a new Uri and this uri will be returned through this methods
4.now create a switch statement on the basis of match(int variable)
5.if case is 100 we insert data
6. inserted result is will be saved in a long variable
7. If the long variable is greater that zero the data inserted successfully and we also created a URI in this condition.
8.After that, we set a notification that's data is changed. Now see the code-
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { SQLiteDatabase database = mHelper.getWritableDatabase(); int match = sUriMatcher.match(uri); //uri Uri returnUri; switch (match){ case TASKS: long inserted = database.insert(DB_Contract.Entry.TASK_TABLE_NAME,null,values); if (inserted > 0){ //success returnUri = ContentUris.withAppendedId(DB_Contract.Entry.CONTENT_URI,inserted); } else { throw new RuntimeException("FAILED TO INSERTED DATA: "+uri); } break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } //notify data has changed if (getContext() != null){ getContext().getContentResolver().notifyChange(uri,null); } return returnUri; }Ok, Now Query method- 1.First, we create an SQLiteDatabase through mHelper and database type must be the readable database.Because we do not insert any data into the database.
2.create an integer variable and initialize it by calling sUriMatcher.match(uri) and pass uri.
3.Now create a new Cursor and this cursor will be returned through this method
4.now create a switch statement on the basis of match(int variable)
5. I f case is 100, then we have to provide all data in the table. or If the case will be 101, we have to provide a single row data
6. query result is will be saved in a cursor
7. If the cursor is not null we have to set Notification uri
See the code-
@Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { //get db final SQLiteDatabase database = mHelper.getWritableDatabase(); //type of uri match int match = sUriMatcher.match(uri); Cursor returnCursor; switch (match){ //all data in a table uri case TASKS: returnCursor = database.query( //table DB_Contract.Entry.TASK_TABLE_NAME, //selected column projection, //section selection, //selection arg selectionArgs, //group by null, //having null, sortOrder); break; // Add a case to query for a single row of data by ID // Use selections and selectionArgs to filter for that ID case TASK_WITH_ID: // Get the task name from the URI String taskID = uri.getPathSegments().get(1); // Selection is the _ID column = ?, and the Selection args = the row ID from the URI String mSelection = DB_Contract.Entry._ID + " = ? "; String[] mSelectionArg = new String[]{taskID}; // Construct a query as you would normally, passing in the selection/args returnCursor = database.query(DB_Contract.Entry.TASK_TABLE_NAME, projection, mSelection, mSelectionArg, null, null, sortOrder); break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } //set notification for data changed assert getContext() != null; returnCursor.setNotificationUri(getContext().getContentResolver(),uri); return returnCursor; }Note: See code comment for better understanding. Update and delete methods are same as those two methods but have some difference. Let's see the code one by one. Follow code comment for better understanding- Update-
@Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { final SQLiteDatabase db = mHelper.getWritableDatabase(); //Keep track of if an update occurs int tasksUpdated; // match code int match = sUriMatcher.match(uri); switch (match) { case TASK_WITH_ID: //update a single task by getting the id String taskId = uri.getPathSegments().get(1); //using selections String whereClause = DB_Contract.Entry._ID + " = ? "; String[] whereArgs = new String[]{taskId}; tasksUpdated = db.update(DB_Contract.Entry.TASK_TABLE_NAME, values, whereClause, whereArgs); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } if (tasksUpdated != 0) { //set notifications if a task was updated assert getContext() != null; getContext().getContentResolver().notifyChange(uri, null); } // return number of tasks updated return tasksUpdated; }Delete-
@Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { final SQLiteDatabase db = mHelper.getWritableDatabase(); int match = sUriMatcher.match(uri); //uri int taskDelete; switch (match) { case TASK_WITH_ID: // Get the id from the URI String taskId = uri.getPathSegments().get(1); // Selection is the _ID column = ?, and the Selection args = the row ID from the URI String whereClause = DB_Contract.Entry._ID + " = ? "; String[] whereArgs = new String[]{taskId}; taskDelete = db.delete(DB_Contract.Entry.TASK_TABLE_NAME, whereClause, whereArgs); break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } if (taskDelete != 0) { // A task was deleted, set notification assert getContext() != null; getContext().getContentResolver().notifyChange(uri, null); } return taskDelete; }One more method left to do. But if you are not exported you database this method is not needed anymore-
@Nullable @Override public String getType(@NonNull Uri uri) { int match = sUriMatcher.match(uri); switch (match) { case TASKS: // directory return "vnd.android.cursor.dir" + "/" + DB_Contract.AUTHORITY + "/" + DB_Contract.PATH_TASKS; case TASK_WITH_ID: // single item type return "vnd.android.cursor.item" + "/" + DB_Contract.AUTHORITY + "/" + DB_Contract.PATH_TASKS; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } }That's it. Now we have CRUDE methods and nor we can access database and inserted data- Now time for full code-
public class DataProvider extends ContentProvider { //use to get all data from this path private static final int TASKS = 100; //use to get single data from a single row private static final int TASK_WITH_ID = 101; //match with which uri private static final UriMatcher sUriMatcher = buildUriMatcher(); private DatabaseHelper mHelper; private static UriMatcher buildUriMatcher() { // Initialize a UriMatcher with no matches by passing in NO_MATCH to the constructor UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); /* *All paths added to the UriMatcher have a corresponding int. For each kind of uri you may want to access, add the corresponding match with addURI. The two calls below add matches for the task directory and a single item by ID. */ matcher.addURI(DB_Contract.AUTHORITY,DB_Contract.PATH_TASKS,TASKS); matcher.addURI(DB_Contract.AUTHORITY,DB_Contract.PATH_TASKS + "/#",TASK_WITH_ID); return matcher; } @Override public boolean onCreate() { //create db instance mHelper = new DatabaseHelper(getContext()); return true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { //get db final SQLiteDatabase database = mHelper.getWritableDatabase(); //type of uri match int match = sUriMatcher.match(uri); Cursor returnCursor; switch (match){ //all data in a table uri case TASKS: returnCursor = database.query( //table DB_Contract.Entry.TASK_TABLE_NAME, //selected column projection, //section selection, //selection arg selectionArgs, //group by null, //having null, sortOrder); break; // Add a case to query for a single row of data by ID // Use selections and selectionArgs to filter for that ID case TASK_WITH_ID: // Get the task name from the URI String taskID = uri.getPathSegments().get(1); // Selection is the _ID column = ?, and the Selection args = the row ID from the URI String mSelection = DB_Contract.Entry._ID + " = ? "; String[] mSelectionArg = new String[]{taskID}; // Construct a query as you would normally, passing in the selection/args returnCursor = database.query(DB_Contract.Entry.TASK_TABLE_NAME, projection, mSelection, mSelectionArg, null, null, sortOrder); break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } //set notification for data changed assert getContext() != null; returnCursor.setNotificationUri(getContext().getContentResolver(),uri); return returnCursor; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { SQLiteDatabase database = mHelper.getWritableDatabase(); int match = sUriMatcher.match(uri); //uri Uri returnUri; switch (match){ case TASKS: long inserted = database.insert(DB_Contract.Entry.TASK_TABLE_NAME,null,values); if (inserted > 0){ //success returnUri = ContentUris.withAppendedId(DB_Contract.Entry.CONTENT_URI,inserted); } else { throw new RuntimeException("FAILED TO INSERTED DATA: "+uri); } break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } //notify data has changed if (getContext() != null){ getContext().getContentResolver().notifyChange(uri,null); } return returnUri; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { final SQLiteDatabase db = mHelper.getWritableDatabase(); int match = sUriMatcher.match(uri); //uri int taskDelete; switch (match) { case TASK_WITH_ID: // Get the id from the URI String taskId = uri.getPathSegments().get(1); // Selection is the _ID column = ?, and the Selection args = the row ID from the URI String whereClause = DB_Contract.Entry._ID + " = ? "; String[] whereArgs = new String[]{taskId}; taskDelete = db.delete(DB_Contract.Entry.TASK_TABLE_NAME, whereClause, whereArgs); break; default: throw new UnsupportedOperationException("Unknown Uri: " + uri); } if (taskDelete != 0) { // A task was deleted, set notification assert getContext() != null; getContext().getContentResolver().notifyChange(uri, null); } return taskDelete; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { final SQLiteDatabase db = mHelper.getWritableDatabase(); //Keep track of if an update occurs int tasksUpdated; // match code int match = sUriMatcher.match(uri); switch (match) { case TASK_WITH_ID: //update a single task by getting the id String taskId = uri.getPathSegments().get(1); //using selections String whereClause = DB_Contract.Entry._ID + " = ? "; String[] whereArgs = new String[]{taskId}; tasksUpdated = db.update(DB_Contract.Entry.TASK_TABLE_NAME, values, whereClause, whereArgs); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } if (tasksUpdated != 0) { //set notifications if a task was updated assert getContext() != null; getContext().getContentResolver().notifyChange(uri, null); } // return number of tasks updated return tasksUpdated; } /* getType() handles requests for the MIME type of data We are working with two types of data: 1) a directory and 2) a single row of data. This method will not be used in our app, but gives a way to standardize the data formats that your provider accesses, and this can be useful for data organization. For now, this method will not be used but will be provided for completeness. */ @Nullable @Override public String getType(@NonNull Uri uri) { int match = sUriMatcher.match(uri); switch (match) { case TASKS: // directory return "vnd.android.cursor.dir" + "/" + DB_Contract.AUTHORITY + "/" + DB_Contract.PATH_TASKS; case TASK_WITH_ID: // single item type return "vnd.android.cursor.item" + "/" + DB_Contract.AUTHORITY + "/" + DB_Contract.PATH_TASKS; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } } }Thank's you once again. Hope you can use the content provider in your project. Happy coding
No comments :