Android Content Providers — Build your own!

.
6 min readMay 29, 2018

--

Learn how to build Content Providers the right way!

Building a custom Content Provider is made by 5 steps:

1. Create a class that extends from the Content Provider and implement the onCreate() method
Extending from Android’s Content Provider class ensures that the new Content Provider will be recognized as a valid provider. In addition, it will override all the necessary methods for manipulating data.

The onCreate() method is called to initialize the provider.

Inside the class you can see 6 methods: onCreate(), insert(), query(), delete(), update() and getType().

All of these methods are required to build a complete Content Provider.

onCreate() is where we should initialize anything we need to setup and access our underlying data source. For now we work with SQLite database. So, it’s a good place to give it a way to open that database. With the db helper object.

We do it by the following steps:
(1) Declaring a private member variable of the DBHelper class
(2) In onCreate() we will assign it to a new DB Helper class passing in the context
(3) onCreate() should now return TRUE

2. Register the new Content Provider in the Android Manifest
Content Providers need to be registered similar to activities. It makes our app knows that the provider exists and knows how to refer to it by name and authority.

Registering the provider in the manifest allows it to be seen by the system so our app will be able to refer to it later on.

EndPass calls to it to a content resolver in our UI code.

A content Resolver different Content Providers based on their unique content authority. The authority is defined in the manifest and it’s typically just the package name of our app. Once a content resolver knows this authority, it can then make direct calls to that provider.

To register a provider we need to declare a provider tag in the manifest and add the following attributes:
(1) name — The name will be the full package name and class
(2) authorities — The authority will be the package name of the app
(3) exported — This attribute determines whether or not our content provider can be accessed by other applications. It can be set to true or false.

3. Define URI’s and add them to the Contract class
URI’s identify the new Content Provider and the different data types it can return. These are needed so later on a Content Resolver can find the provider and the specific data we want to access just based on a given URI.

After defining the URI’s we need to update the Contract class to include all URI’s and string constants that will help you refer to the most commonly used URI’s.

We need to tell the content provider how to access our data. URI’s tell content resolver two things:
(1) Identify your provider
(2) Identify different type of data that the provider can work with

All content URI’s start with a base that include a scheme, followed by an authority. Then after that is the path, that indicates the specific data that you’re interested in.

This is the portion of the URI that will help the provider select the correct data and we need to define it in the code.

A lot of providers will have multiple directories of data to work with and will therefore need multiple URI paths.

URIMatchers have matching capabilities similar to regex pattern matching, but simpler. URIMatcher recognize only two wildcard characters:
(1) (Asterix) * — Matches a string of any length
(2) (Hash symbol) # — Matches a string of numeric characters

These symbols can be combined with each other or a specific URI path segments to define a complete URI structure.

It is a best practice to store any URI components that we commonly use as constants in the contract class.

Base URI build on scheme and authority, which is a unique reference to the provider. And all the URI’s that our provider recognizes starts with these two pieces as the base.

In the contract we will define:
(1) The aurhority
(2) The base content (URI scheme + authority)
(3) The path (points to a specific table or file)
(4) The Content URI — Inside our table class. Combines of all the constants above.

4. Build a URIMatcher to match URI patterns to integers
URIMatcher is a class that helps a Content Provider recognize and respond correctly to different types of URI’s

URIMatcher determined what kind of URI the provider receives and match it to an integer constant, so that we can easily make a switch statement that will make our code much more readable.

There are 3 steps we need to implement inside our provider:
(1) Define final integer constants for the directory of the table and for a single item. It’s convenient to use rounded numbers for tables (like 100, 200, 300, etc.) and related ints for fewer rows of data (like 101, 102, etc.)
(2) Define a static buildUriMatcher method that associates URI’s with their int match.
(3) Declare a static variable for the UriMatcher that we built in step 2.

5. Implement the required CRUD methods
We need to implement the required CRUD methods to access and change data.

How data moves from the UI to the database and back?

UI > Content Resolver (URI) > Content Provider > URIMatcher > SQL Code > Database

Our app is querying for data to display in the UI. First, from the UI code, the app will get a Content Resolver and call query on it, passing in the URI for the exact provider and data you want to read. Then the resolver finds the correct Content Provider based on the authority of the passed in URI and passes on the query. The provider’s query function will then use the URIMatcher you’ve built to decide how to react to the passed in URI and determine what kind of data to retrieve. Weather that’s one row of data or the whole directory or some other specific selection. Based on the match the query function will basically translate the URI and other parameters into the correct SQL code for selected data. Using the URIMatcher and the code for your query, the provider will then retrieve the desired data from the underlying database.

From the database the call travels all the way back to the resolver in our UI code and returns a cursor with that data. The best way to asynchronously load data from any ContenProvider is with CursorLoader.

There are 6 functions that every Content Provider is required to have:
(1) onCreate() — Initializes the provider
(2) Insert() — Will take the content URI which tells the correct directory to insert data into, and a ContentValues object that contains the new data to insert. After the data is inserted, this returns a newly created Content URI that tells you the location of the inserted data.
(3) query() — Asks for data from our Content Provider. This returns a cursor that contains row(s) of data that the query as asked for.
(4) update() — Takes the same parameters as entered, so it knows where to update data by the URI, and with what ContentValues. This will return an integer value for the number of rows that were updated.
(5) delete() — Needs to know the URI that points to the row, or rows, to delete. This should return the number of rows deleted.
(6) getType() — Returns the MIME type (a way to identify what format the content is in) of the content being returned.

REFERENCES:

You can find much more at the free course Developing Android Apps by Google on the Udacity website over here: (check it out!)

Android App Development | Udacity

--

--