1.1. What is a content provider
Content provider is one of the four components of Android that can share data from your app to external users
Content providers unify the way data is accessed without having to take different access policies for different data types
Content providers encapsulate data, exposing only the data we want to provide to other programs
Data changes in the content provider can be monitored
1.2. Create a content provider
Define class inheritance ContentProvider, overriding internal methods as needed
You need to specify the name and authorities property in the configuration,<provider> tag in the <application> node of the manifest file
Name is the class name, and the package name starts with the program pack, with "." Begin
Authorities: is the path to access provider, the only
The URI represents the data to be manipulated, consisting of scheme, authorites, path three parts
Content://cn.itcast.provider.itcast/person
Scheme: Fixed to content, on behalf of access provider
The Authorites property in the Authorites:<provider> node
Path: program-defined paths that can be defined according to business logic
1.3. Complete the Crud method
The URI is passed in when the program calls the Crud method
We use URIs to determine the data the caller wants to manipulate.
You can use the tool class Urimatcher to determine the URI
Adduri method to add a URI
The match method can match a URI to determine its type
Operating data based on business logic
1.4. Complete the GetType method
Y if the return data is a single data: Vnd.android.cursor.item
Y if the return data is multiple data: Vnd.android.cursor.dir
public class Personprovider extends Android.content.ContentProvider {private static final int person = 0; private static final int person_id = 1; Private Urimatcher Matcher; Private Dbopenhelper Helper; @Override public boolean onCreate () {matcher = new Urimatcher (urimatcher.no_match); Matcher.adduri ("Com.demo.sqlite.provider", "person", person); Add a URI that can match Matcher.adduri ("Com.demo.sqlite.provider", "person/#", person_id); Helper = new Dbopenhelper (GetContext ()); return true; @Override public Cursor query (URI uri, string[] projection, string selection, string[] Selectionargs, String Sorto Rder) {switch (Matcher.match (URI)) {//URI Match case person_id:string idselection = "ID =" + Contenturis.parseid (URI); Converts the last path segment to a long. Note here that the string is assembled selection = Selection = = null? Idselection:idselection + "and" + selection; Case Person: Sqlitedatabase db = Helper.getreadabledatabase (); return db.query ("person", projection, selection, Selectionargs, NULL, NULL, sortOrder); Default:throw new IllegalArgumentException ("No Match uri" + uri); }} @Override public uri insert (URI uri, contentvalues values) {switch (Matcher.match (URI)) {case Person:sqlitedatabase db = Helper.getwritabledatabase (); Long id = db.insert ("person", null, values); Use the Db.insert () method to insert data, return ID//and DB. Excesql (SQL) to insert data, return void//Return Uri.parse ("content://com.demo.sqlite.provider/person/" + ID); Same as the next sentence return Contenturis.withappendedid (URI, id); Appends the given ID to the end of the path. Default:throw new IllegalArgumentException ("No Match uri" + uri); }} @Override Public int Delete (URI Uri, String selection, string[] selectionargs) {switch (Matcher.match (URI)) {case Person_ Id:long id = contenturis.parseid (URI); Selection = Selection = = null? "id =" + ID: "id =" +id + "and" +selection; Case Person:sqlitedatabase db = Helper.getwritabledatabase (); Return:the number of rows affected return Db.delete ("person", selection, Selectionargs); Default:throw new IllegalArgumentException ("No Match uri" + uri); }} @Override public int update (URI uri, contentvalues values, String selection, string[] Selectionargs) { Switch (Matcher.match (URI)) {case Person_id:long ID = Contenturis.parseid (URI); Selection = Selection = = null? "id =" + ID: "id =" + ID + "and" + selection; Case Person:sqlitedatabase db = Helper.getwritabledatabase (); @return The number of rows AFFECTed return Db.update ("person", values, selection, Selectionargs); Default:throw new IllegalArgumentException ("No Match uri" + uri); }} @Override public String getType (URI uri) {switch (Matcher.match (URI)) {case PERSON_ID: return "Vnd.android.cursor.item/person"; Case Person:return "Vnd.android.cursor.dir/person"; Default:throw new IllegalArgumentException ("No Match uri" + uri); } }
1.5. Access to content providers
Y get Contentresolver object through context
You can access the content provider by invoking the method of the Contentresolver object
private static final String TAG = "Providertest"; Query id = $ public void TestQuery1 () {//Contentresolver call ContentProvider provided method Contentresolver R Esolver = GetContext (). Getcontentresolver (); Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); Cursor C = resolver.query (URI, new string[] {"id", "name", "Balance"}, "id =?", new string[] {"$"}, NULL); if (C.movetonext ()) {Person person = new Person (c.getint (0), c.getstring (1), C.getint (2)); Logger.i (TAG, person.tostring ()); }}//query all person public void TestQuery2 () {//Contentresolver call the method provided by ContentProvider Conten Tresolver resolver = GetContext (). Getcontentresolver (); Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); Cursor C = resolver.query (URI, NULL, NULL, NULL, or NULL); while (C.movetonext ()) {Person person = new Person (c.getint (0), c.getstring (1), C.getint(2)); Logger.i (TAG, person.tostring ()); }//query by the ID of the person public void TestQuery3 () {//through the Contentresolver call method provided by the ContentProvider Contentresolver resolver = GetContext (). Getcontentresolver (); Uri uri uri = uri.parse ("CONTENT://COM.DEMO.SQLITE.PROVIDER/PERSON/55"); Cursor C = resolver.query (URI, NULL, "name =?", new string[] {"ashia_54"}, NULL); while (C.movetonext ()) {Person person = new Person (c.getint (0), c.getstring (1), C.getint (2)); Logger.i (TAG, person.tostring ()); }} public void Testinsert () {Contentresolver resolver = GetContext (). Getcontentresolver (); Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); Contentvalues values = new Contentvalues (); person person = new person ("Another person URI insert", 7000); Values.put ("Name", Person.getname ()); Values.put ("Balance", person.getbalance ()); Uri reuri = Resolver.insert (URI, values); Cursor C = resolver.query (Reuri, NULL, NULL, NULL, or NULL); if (C.movetonext ()) {Person Reperson = new Person (c.getint (0), c.getstring (1), C.getint (2)); Logger.i (TAG, reperson.tostring ()); }} public void Testdelete () {//Contentresolver:this class provides applications access to the content Model. Contentresolver resolver = GetContext (). Getcontentresolver (); Uri url = uri.parse ("content://com.demo.sqlite.provider/person/121"); Forget add =?, exception as follows//android.database.sqlite.SQLiteException:bind or column index out of range long id = RE Solver.delete (URL, "name =?", new string[] {"Zhangsan"}); LOGGER.I (TAG, id + ""); id = resolver.delete (URL, null, NULL); LOGGER.I (TAG, id + ""); The public void Testdeleteall () {Contentresolver resolver = GetContext (). Getcontentresolver (); Uri url = uri.parse ("contEnt://com.demo.sqlite.provider/person "); int deletenum = resolver.delete (URL, null, NULL); Logger.i (TAG, Deletenum + ""); The public void Testupdate () {Contentresolver resolver = GetContext (). Getcontentresolver (); Uri uri = uri.parse ("content://com.demo.sqlite.provider/person/122"); Contentvalues values = new Contentvalues (); Values.put ("balance", 8000); int update = Resolver.update (URI, values, "balance =?", new string[] {"9000"}); LOGGER.I (TAG, update + ""); The public void Testupdatebyid () {Contentresolver resolver = GetContext (). Getcontentresolver (); Contentvalues values = new Contentvalues (); Values.put ("Name", "new name"); Values.put ("balance", 7000); Values.put ("id", 2); Uri uri = uri.parse ("content://com.demo.sqlite.provider/person/123"); int update = Resolver.update (URI, values, NULL, NULL); LOGGER.I (TAG, update + ""); }//URI write error, exception//JAVA.lang.illegalargumentexception:unknown URI//primary Key ID Duplicate, exception//Android.database.sqlite.SQLiteConstraintExceptio n public void Testgettype () {Contentresolver resolver = GetContext (). Getcontentresolver (); Uri uri = uri.parse ("CONTENT://COM.DEMO.SQLITE.PROVIDER/PERSON/1"); Logger.i (TAG, Resolver.gettype (URI)); URI = Uri.parse ("Content://com.demo.sqlite.provider/person"); Logger.i (TAG, Resolver.gettype (URI)); }
1.6. Monitor content provider Data changes
Y can notify other program data changes in content provider
Get Contentresolver through the Getcontentresolver () method of the context
Call its Notifychange () method to send data modification notifications
Y can monitor data changes through Contentobserver in other programs
Get Contentresolver through the Getcontentresolver () method of the context
Calls its Registercontentobserver () method to specify that a URI is registered Contentobserver
Custom Contentobserver, overriding the OnChange () method to get the data
Send data modification Notifications
Public URI insert (URI uri, contentvalues values) { switch (Matcher.match (URI)) {case Person : Sqlitedatabase db = Helper.getwritabledatabase (); Long id = db.insert ("person", null, values); Notify registered observers that a row is updated. Register observer //@param observer The Observer that originated the changes, may be null //Generate a change of observer. Here is the provider belt To change, pass null this.getcontext (). Getcontentresolver (). Notifychange (URI, null); Send change notification //return uri.parse ("content://com.demo.sqlite.provider/person/" + ID); Return Contenturis.withappendedid (URI, id); Default: throw new IllegalArgumentException ("No Match uri" + uri); } }
Defines a contentobserver that listens for changes to the content provider of the URI
Protected static final String TAG = "observeractivity"; /** called when the activity is first created. */@Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.main); Define a CONTENTOBSERVER contentobserver observer = new Contentobserver (new Handler ()) {/** * Returns TRUE if this observer was interested in notifications for * changes made through the cursor the Observ ER is registered with. *///whether to pass your own changes @Override public boolean deliverselfnotifications () {Retu RN Super.deliverselfnotifications (); }/** * This method was called when a change occurs to the cursor that was * being observ Ed. * * @param Selfchange * True if the update is caused by a call to commit on * The CursOr is being observed. *///when the monitored content has changed, call the method @Override public void OnChange (Boolean selfchange) { LOGGER.I (TAG, "the supervisor hears the change"); Print out the last inserted information contentresolver resolver = Getcontentresolver (); Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); SELECT * FROM person ORDER by ID DESC LIMIT 1; Cursor C = resolver.query (URI, NULL, NULL, NULL, "ID DESC LIMIT 1"); if (C.movetonext ()) {String result = "id =" + c.getint (0) + ", name =" + c.getstring (1) + ", balance = "+ c.getint (2); LOGGER.I (TAG, result); Toast.maketext (Observeractivity.this, result, 1). Show (); }//Parent class did not do any implementation super.onchange (Selfchange); } }; Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); Register a contentObserver/* * @param notifyfordescendents * If true changes to URIs beginning with URI would also C Ause notifications to be sent. * Iffalse only changes to the exact URI specified by URI would cause notifications to be sent. * If true, than any URI values at or below the specified URI would also trigger a match. *///whether to listen for other URIs starting with "uri" Getcontentresolver (). Registercontentobserver (URI, TRUE, observer); }
Monitor content changes and automatically update the ListView via Contentobserver
Bt_insert = (Button) Findviewbyid (R.id.bt_insert); Bt_insert.setonclicklistener (New Onclicklistener () {public void OnClick (View v) {Contentresolv ER resolver = ListViewSimpleCursorAdapterActivity.this.getContentResolver (); Uri url = uri.parse ("Content://com.demo.sqlite.provider/person"); Contentvalues values = new Contentvalues (); Values.put ("name", "Test Name"); Values.put ("balance", 3000); Resolver.insert (URL, values); } }); Lv_person.setonitemclicklistener (New Myonitemclicklistener ()); Uri uri = uri.parse ("Content://com.demo.sqlite.provider/person"); Getcontentresolver (). Registercontentobserver (URI, False, new Mycontentobserver (New Handler ())); public class Mycontentobserver extends Contentobserver {public mycontentobserver (Handler Handler) {sup ER (handler); } @Override public void OnchaNge (Boolean Selfchange) {//When the listening content has changed, the data in the LV is updated with the Cursor c = new Persondao (Listviewsimplecursorada pteractivity.this). Queryallcursor (); Simplecursoradapter adapter = new Simplecursoradapter (listviewsimplecursoradapteractivity.this,//R.la Yout.listview_item,//C,//new string[] {"_id", "name", "balance"},// New int[] {r.id.tv_id, r.id.tv_name, r.id.tv_balance}); Lv_person.setadapter (adapter); Lv_person.setonitemclicklistener (New Myonitemclicklistener ()); Super.onchange (Selfchange); LOGGER.I (TAG, "OnChange"); } }
Error
URI write error, exception Java.lang.IllegalArgumentException:Unknown URI
Duplicate primary key ID, exception android.database.sqlite.SQLiteConstraintException
The interface always closes automatically when you test a ListView update
If you are a content provider and a content observer,
When you change content in a test case, the app forces the exit
Go ContentProvider content Providers