ContentProvider直譯過來就是內容提供者,主要做用就是A應用提供接口給B應用調用數據,和以前介紹的sharedPreference和直接開放文件訪問相似,都是共享應用程序數據,不一樣的是以前的兩種文件格式可能徹底不一樣,如可能爲xml,txt,sql等等,這裏ContentProvider返回的數據格式是統一的,所以應用的更爲普遍一點.java
這裏使用的是A應用經過ContentProvider共享數據給B應用.這裏A應用用的是前文中的android_db裏的person表.B應用是新建的android_content_provider程序.android
建立好了應用程序之後,git
/android_content_provider/src/com/example/android_content_provider/ContentProvider.javagithub
package com.example.android_content_provider; import android.app.Activity; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; public class ContentProvider extends Activity { private static String tag = "ContentProvider.class"; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //內容解析者 ContentResolver contentResolver = getContentResolver(); Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/persons"); Cursor cursor = contentResolver.query(uri, null, null, null, null); while(cursor.moveToNext()){ String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); System.out.println("name:"+name+" age:"+age); Log.d(tag,"用戶名:"+name+" 年齡:"+age); } } }
3.android_db開放共享數據接口sql
/android_db/AndroidManifest.xml數據庫
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.amos.android_db" android:versionCode="1" android:versionName="1.0"> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.amos.android_db"></instrumentation> <uses-sdk android:minSdkVersion="7"/> <application android:label="@string/app_name"> <uses-library android:name="android.test.runner"/> <activity android:name="MyActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!--給內容提供者提供定義一個uri,通常建議使用包名+類名,以供其它程序調用 --> <provider android:authorities="com.amos.android_db.provider.PersonProvider" android:name=".provider.PersonProvider"> </provider> </application> </manifest>
/android_db/src/com/amos/android_db/provider/PersonProvider.java
package com.amos.android_db.provider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.util.Log; import com.amos.android_db.MyDBHelper; import com.amos.android_db.dao.Person; import com.amos.android_db.dao.PersonDao; import java.util.List; /** * Created by amosli on 14-6-17. */ public class PersonProvider extends ContentProvider { //建立一個路徑識別器 //常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼,也就是說若是找不到匹配的類型,返回-1 private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int ALL_PERSON = 1; private static final int PERSON = 2; private static final int OTHER = 3; private static String tag="PersonProvider.class"; static{ //1.指定一個路徑的匹配規則 //若是路徑知足content://com.amos.android_db.provider.PersonProvider/persons,返回值就是(ALL_PERSON)=1 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","persons",ALL_PERSON); //2.若是路徑知足content://com.amos.android_db.provider.PersonProvider/person/3,返回值就是(PERSON)=2 //#號爲通配符 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","person/#",PERSON); //3.若是路徑知足content://com.amos.android_db.provider.PersonProvider/other,返回值就是(OTHER)=3 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","other",OTHER); } /** * 通常是對象第一次被建立時調用的方法 * * @return */ @Override public boolean onCreate() { return false; } /** * 讓別人去調用返回結果 * * @param uri * @param projection 選擇的列 * @param selection 查詢條件 * @param selectionArgs 查詢條件的value * @param sortOrder 排序 * @return */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int result = uriMatcher.match(uri); switch(result){ //若是路徑知足content://com.amos.android_db.provider.PersonProvider/persons,返回值就是(ALL_PERSON)=1 case ALL_PERSON: PersonDao dao = new PersonDao(this.getContext()); return dao.findAllByCursor(); //2.若是路徑知足content://com.amos.android_db.provider.PersonProvider/person/3,返回值就是(PERSON)=2 case PERSON: long id = ContentUris.parseId(uri); SQLiteDatabase database = new MyDBHelper(this.getContext()).getReadableDatabase(); if(database.isOpen()){ database.execSQL("select * person where personid = "+id); return database.query("person", null, "personid", new String[]{id + ""}, null, null, null); //不要關閉數據庫,不然就沒有數據了. } case OTHER: Log.d(tag,"我是其餘匹配規則!"); break; default: throw new RuntimeException("出錯了!!"); } return null; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
首先,將android_db部署到avd上,其次,運行android_content_provider項目,最後,查看log輸出.app
..... at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.example.android_content_provider.ContentProvider.onCreate(ContentProvider.java:21) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611) .....
這種問題頗有多是路徑名稱不對,注意提供的接口名稱保持一致;而且保證獲取數據的接口是正常的,即android_db裏獲取person表的內容是正常的.ide
注意選擇Android--->選擇要查看Log的進程--->點擊上面的雙向箭頭進行切換日誌展現信息.測試
上面已經實現了查詢的接口,這裏將實現另外三個接口:this
//4.插入數據,若是路徑知足content://com.amos.android_db.provider.PersonProvider/insert,返回值就是(INSERT)=4 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "insert", INSERT); //5.刪除數據,若是路徑知足content://com.amos.android_db.provider.PersonProvider/delete,返回值就是(DELETE)=5 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "delete", DELETE); //6.更新數據,若是路徑知足content://com.amos.android_db.provider.PersonProvider/update,返回值就是(UPDATE)=6 uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "update", UPDATE);
對應的實現:
@Override public Uri insert(Uri uri, ContentValues values) { //content://com.amos.android_db.provider.PersonProvider/insert int result = uriMatcher.match(uri); switch (result) { case INSERT: SQLiteDatabase database = myDBHelper.getWritableDatabase(); if (database.isOpen()) { database.insert("person", null, values); } return uri; default: throw new RuntimeException("沒法識別該URI,出錯了!!"); } } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { //刪除操做 //content://com.amos.android_db.provider.PersonProvider/delete int result = uriMatcher.match(uri); switch (result) { case DELETE: SQLiteDatabase database = myDBHelper.getWritableDatabase(); return database.delete("person", selection, selectionArgs); default: throw new RuntimeException("沒法識別該URI,出錯了!!"); } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { //更新操做 //content://com.amos.android_db.provider.PersonProvider/update int result = uriMatcher.match(uri); switch (result) { case UPDATE: SQLiteDatabase database = myDBHelper.getWritableDatabase(); return database.update("person", values, selection, selectionArgs); default: throw new RuntimeException("沒法識別該URI,出錯了!!"); } }
//返回值的類型
@Override public String getType(Uri uri) { int result = uriMatcher.match(uri); switch (result){ case ALL_PERSON: return "List<Person>"; case PERSON: return "Person"; default:return null; } }
2)測試
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.ContentProviderTest" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="7"/> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.ContentProviderTest"/> <application android:label="@string/app_name"> <uses-library android:name="android.test.runner"/> <activity android:name="MyActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
加入加粗的兩行,配置好測試的環境.
/ContentProviderTest/src/com/example/ContentProviderTest/test/TestCase.java
package com.example.ContentProviderTest.test; import android.content.ContentResolver; import android.content.ContentValues; import android.net.Uri; import android.test.AndroidTestCase; /** * Created by amosli on 14-6-19. */ public class TestCase extends AndroidTestCase { public void testInsert(){ ContentResolver contentResolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/insert"); ContentValues values = new ContentValues(); values.put("name", "bill"); values.put("age", 18); contentResolver.insert(uri, values); } public void testDelete(){ ContentResolver contentResolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/delete"); contentResolver.delete(uri,"name=?",new String[]{"amos96"}); } public void testUpdate(){ ContentResolver contentResolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/update"); ContentValues contentValues = new ContentValues(); contentValues.put("name","jack"); contentValues.put("age",30); contentResolver.update(uri,contentValues,"name=?",new String[]{"amos97"}); } }
3)效果圖:
插入數據(insert方法),bill
刪除數據(delete方法),amos96
更新數據(update方法 ),amos97
本文源碼:
https://github.com/amosli/android_basic/tree/android_db
https://github.com/amosli/android_basic/tree/content_provoider
https://github.com/amosli/android_basic/tree/android_contentProviderTest