Download Overview of Content Providers Creating a Content Provider

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

SQL wikipedia , lookup

Open Database Connectivity wikipedia , lookup

Database wikipedia , lookup

Microsoft Jet Database Engine wikipedia , lookup

Entity–attribute–value model wikipedia , lookup

Functional Database Model wikipedia , lookup

Extensible Storage Engine wikipedia , lookup

Clusterpoint wikipedia , lookup

Relational model wikipedia , lookup

Database model wikipedia , lookup

Transcript
Overview of Content Providers
A content provider manages access from a central database. In practice, the provider client usually
supplies its own UI to work and access the data. However the main purpose of a content provider is
to provide a similar method for multiple applications to access the same data in an efficient and
secure manner.
All content providers are arranged in the same way as a relational database. For example, the user
dictionary, which holds all user-defined words, is organized as so:
word
app id
frequency
locale
_ID
mapreduce
user1
100
en_US
1
precompiler
user14
200
fr_FR
2
applet
user2
225
fr_CA
3
const
user1
255
pt_BR
4
int
user5
100
en_UK
5
Each row is an instance of a word- with its spelling and the different attributes.
Each column is a row of similar data, such as the frequency of each word.
The _ID column is the primary key column. Most databases don't need an _ID column to be the
primary key, however if you want to put the data into a ListView object, you will need a _ID
column.
Creating a Content Provider
In order to create a content provider, you implement the central class for Android; which is
ContentProvider, which will act as the interface between the provider (database) and applications
accessing that data. In the case that you do decide to use a content provider over more typical
memory for your application; keep in mind the following:
- You require a means to store complex data or files that application other than your content
provider can access.
- You require methods to search and sort a large amount of information.
- You need users to copy complex data from your database to other applications.
You can store your data in two main formats:
File data – where your organized data such as pictures (png, jpg) audio (mp3, wav) or videos (mp4,
etc) in a manner that is easily accessible and retrievable from another program.
“Structured” data – Data as seen in the table above; usually stored in an aray or table with rows and
columns. Each column represents an individual aspect of that data and each row an element
of that data.
Now on creating an actual content provider, you will need to:
1. Implement the ContentProvider class
2. Define the provider's authority string, its content URIs, and the column names. You also need to
define permissions, handling intents and any extra data.
3. Add any other other optional pieces, such as sample data or synchronization with cloud platforms.
Available Data Sources
The following forms of data storage available for Android are:
- An SQLite database API used by Android providers to store tabular data. You can use the
SQLiteOpenHelper class to create databases and the SQLiteDatabase class to access the database.
- To store file-orientated data, there are file-orientated APIs within Android for that purpose. You
can read more about them in the topic Data Storage on the official Android website at
(http://developer.android.com/guide/topics/data/data-storage.html)
- To work with network-based data, or synchronizing data from a network to a local device, you can
utilize the classes in the java.net and android.net classes. You can read the an example of
synchronization on the Android website at (http://developer.android.com/samples/index.html)
A few considerations to take in mind while creating your database:
- While using tabular data, there should always have a “primary key” column, which has a unique
integer number for each row (each element of data). This allows you to link the row to related rows
in other tables, and for searching and retrieving data. Though you can use any name for this column,
using _ID is recommended, as an _ID column is required to display results in a ListView after
searching a ContentProvider for content.
- If you want to save/organize large files that would not necessarily fit in a table like pictures or
videos, it is best to store the data in a file and provide indirect access to that file, in which case you
would need to use a ContentResolver file method to access the data.
- Use the Binary Large OBject (BLOB) to store data that varies in size or structure.
Designing Content URIs
A content URI is the URI that identifies all data in your provider. Essentially the content URI is the
symbolic name of your provider and the main method of accessing information. The content URI
has two main parts; the symbolic name of the provider called the authority, and the pathname that
points to a table or file called the path. Additionally there is an optional part called the id which
you can use to access a single row from a table.
The authority is the name of the content provider, and by convention it is usually named by
combining the package name of your Android program and the name of your Android application.
So if your package name is “com.example.androidContentProvider” then the name of your provider
by convention will be “com.example.androidContentProvider.provider”.
Also by convention, path names are created by appending the path name to the authority via
traditional file structure systems. So to access “table1” from the provider we specified above, we
will append the pathname “table1” to “com.example.androidContentProvider.provider” to create
“com.example.androidContentProvider.provider/table1”.
Content URI Patterns
As mentioned above, using the contentURI format of “authority+pathname” to access a table from
the your ContentProvider, (i.e com.example.androidContentProvider.provider/table1). We can use
the additional 'id' part by adding a number to the end of your pathname so we can access a single
row. All search queries are returned in a Cursor object which is displayed in a ListView using a
CursorAdapter.
However, if you would want to perform additional operations on more than just one single row, you
can use the provider API with the included class UriMatcher to do just that. There are a few special
characters that you can use to widen your search:
* : Matches a string of any valid characters of any length.
# : Matches a string of numeric characters of any length.
content://com.example.androidContentProvider.provider/*
Will match every contentURI in the provider.
content://com.example.androidContentProvider.provider/table2/*
Matches all content in table2, but no content in table1 or table3 or etc.
content://com.example.androidContentProvider.provider/table2/#
Will match a single row from the provider under table2.
Using the combination of wildcard characters and the UriMatcher.addURI() and
UriMatcher.match(uri) methods, it then becomes possible to perform special actions using them as
shown in the example below:
public class ExampleProvider extends ContentProvider {
...
// Creates a UriMatcher object.
private static final UriMatcher sUriMatcher;
...
/*
* The calls to addURI() go here, for all of the content URI patterns that the
provider
* should recognize. For this snippet, only the calls for table 3 are shown.
*/
...
/*
* Sets the integer value for multiple rows in table 3 to 1. Notice that no
wildcard is used
* in the path
*/
sUriMatcher.addURI("com.example.app.provider", "table3", 1);
/*
* Sets the code for a single row to 2. In this case, the "#" wildcard is
* used. "content://com.example.app.provider/table3/3" matches, but
* "content://com.example.app.provider/table3 doesn't.
*/
sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
...
// Implements ContentProvider.query()
public Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
...
/*
* Choose the table to query and a sort order based on the code returned for
the incoming
* URI. Here, too, only the statements for table 3 are shown.
*/
switch (sUriMatcher.match(uri)) {
// If the incoming URI was for all of table3
case 1:
if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
break;
// If the incoming URI was for a single row
case 2:
/*
* Because this URI was for a single row, the _ID value part is
* present. Get the last path segment from the URI; this is the _ID
value.
* Then, append the value to the WHERE clause for the query
*/
selection = selection + "_ID = " uri.getLastPathSegment();
break;
default:
...
// If the URI is not recognized, you should do some error handling here.
}
// call the code to actually do the query
}
Implementing the ContentProvider Class
The abstract class ContentProvider manages access to a structured set of data by handling requests
from other applications. Being an abstract class, there are six methods that will need to be
implemented when you create a ContentProvider.
Cursor query (Uri contentUri, String[] projection, String selection, String[] selectionArgs, String
sortOrder)
Query is implemented to return search requests from your provider. The query method must return a
Cursor object, even in the case that the search query does not match any data in your provider; an
empty Cursor object should be returned. An example of an implementation of query() is below:
// Request a specific record.
Cursor managedCursor = managedQuery(
ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
projection,
// Which columns to return.
null,
// WHERE clause.
null,
// WHERE clause value substitution
People.NAME + " ASC");
// Sort order.
Another implementation from the helper class SQLiteQueryBuilder
// SQLiteQueryBuilder is a helper class that creates the
// proper SQL syntax for us.
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
// Set the table we're querying.
qBuilder.setTables(DATABASE_TABLE_NAME);
// If the query ends in a specific record number, we're
// being asked for a specific record, so set the
// WHERE clause in our query.
if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
qBuilder.appendWhere("_id=" + uri.getPathLeafId());
}
// Make the query.
Cursor c = qBuilder.query(mDb,
projection,
selection,
selectionArgs,
groupBy,
having,
sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
int insert (Uri contentUri, ContentValues values)
uri
The content:// URI of the insertion request. Cannot be null.
values A set of column_name/value pairs to add to the database. Cannot be null.
Inserts a new row in your database. Returns the number of rows inserted.
int update (Uri contentUri, ContentValues values, String selection, String[] selectionArgs)
Update a row in your database. Returns the number of rows updated.
uri
The URI to query. This can potentially have a record ID if this is an update request for a
specific record.
values A set of column_name/value pairs to update in the database. This must not be null.
selection
An optional filter to match rowws to update
int delete (Uri contentUri, String selection, String[] selectionArgs)
Deletes one or more rows from your provider. Returns the number of rows affected/deleted.
uri
- The full URI to query, including a row ID (if a specific record is requested).
selection
An optional restriction to apply to rows when deleting.
String getType (Uri contentUri)
Returns the MIME type of the given URI (i.e vnd.android.cursor.item – for a single record,
vnd.android.cursor.dir/ – for multiple items.)
uri
the URI to query.
boolean onCreate ()
This will implement and create your content provider on startup. The actual creation of the
ContentProvider should be delayed until a ContentResolver requests or accesses a ContentProvider.
Returns true if the ContentProvider was successfully started; false otherwise.
Your implementation of onCreate() may depend on your extending the ContentProvider or the
SQLiteOpenHelper class. The example below is an example of the ContentProvider onCreate()
public class ExampleProvider extends ContentProvider
/*
* Defines a handle to the database helper object. The MainDatabaseHelper class is
defined
* in a following snippet.
*/
private MainDatabaseHelper mOpenHelper;
// Defines the database name
private static final String DBNAME = "mydb";
// Holds the database object
private SQLiteDatabase db;
public boolean onCreate() {
/*
* Creates a new helper object. This method always returns quickly.
* Notice that the database itself isn't created or opened
* until SQLiteOpenHelper.getWritableDatabase is called
*/
mOpenHelper = new MainDatabaseHelper(
getContext(),
// the application context
DBNAME,
// the name of the database)
null,
// uses the default SQLite cursor
1
// the version number
);
return true;
}
...
// Implements the provider's insert method
public Cursor insert(Uri uri, ContentValues values) {
// Insert code here to determine which table to open, handle error-checking,
and so forth
...
/*
* Gets a writeable database. This will trigger its creation if it doesn't
already exist.
*
*/
db = mOpenHelper.getWritableDatabase();
}
}
And the following is an implementation of SQLIteOpenHelper
// A string that defines the SQL statement for creating a table
private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
"main " +
// Table's name
"(" +
// The columns in the table
" _ID INTEGER PRIMARY KEY, " +
" WORD TEXT"
" FREQUENCY INTEGER " +
" LOCALE TEXT )";
...
/**
* Helper class that actually creates and manages the provider's underlying data
repository.
*/
protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
/*
* Instantiates an open helper for the provider's SQLite data repository
* Do not do database creation and upgrade here.
*/
MainDatabaseHelper(Context context) {
super(context, DBNAME, null, 1);
}
/*
* Creates the data repository. This is called when the provider attempts to open
the
* repository and SQLite reports that it doesn't exist.
*/
public void onCreate(SQLiteDatabase db) {
// Creates the main table
db.execSQL(SQL_CREATE_MAIN);
}
}
SQLiteOpenHelper already implements many operations that