ContentProvider 提供了一個(gè)接口用來(lái)發(fā)布數(shù)據(jù)尖淘,通過(guò)ContentResolver 來(lái)使用該數(shù)據(jù)叹哭。它們?cè)试S將使用數(shù)據(jù)的應(yīng)用程序組件和底層數(shù)據(jù)源分離開(kāi)來(lái)晰绎,并提供一種通用的機(jī)制來(lái)允許一個(gè)應(yīng)用程序共享它們的數(shù)據(jù)或者使用其它應(yīng)用程序供的數(shù)據(jù)彼硫。
一吃溅、Uri介紹
Uri代表要操作的數(shù)據(jù)溶诞,Uri主要包含了兩部分信息:
- 需要操作的ContentProvider
- 對(duì)ContentProvider中的什么數(shù)據(jù)進(jìn)行操作
URI主要分三個(gè)部分:scheme
, authority
and path
。其中authority
又分為host
和port
决侈。
- 格式如下:
scheme://host:port/path
ContentProvider(內(nèi)容提供者)的scheme已經(jīng)由Android所規(guī)定螺垢, scheme為:content://主機(jī)名(或叫Authority)用于唯一標(biāo)識(shí)這個(gè)ContentProvider,外部調(diào)用者可以根據(jù)這個(gè)標(biāo)識(shí)來(lái)找到它赖歌。路徑(path)可以用來(lái)表示我們要操作的數(shù)據(jù)枉圃,路徑的構(gòu)建應(yīng)根據(jù)業(yè)務(wù)而定。
如下以person 表為例
- 要操作person表中id為10的記錄庐冯,可以構(gòu)建這樣的路徑:/person/10
- 要操作person表中id為10的記錄的name字段讯蒲, person/10/name
- 要操作person表中的所有記錄,可以構(gòu)建這樣的路徑:/person
- 要操作xxx表中的記錄肄扎,可以構(gòu)建這樣的路徑:/xxx
使用Uri類中的parse()方法把一個(gè)字符串轉(zhuǎn)換成Uri墨林,如下:
Uri uri = Uri.parse("content://com.cfox.contentprovid.PersonProvider/person")
當(dāng)然要操作的數(shù)據(jù)不一定來(lái)自數(shù)據(jù)庫(kù),也可以是文件犯祠、xml或網(wǎng)絡(luò)等其他存儲(chǔ)方.
二旭等、UriMatcher和ContentUris使用介紹
因?yàn)閁ri代表了要操作的數(shù)據(jù),所以我們經(jīng)常需要解析Uri衡载,并從Uri中獲取數(shù)據(jù)搔耕。Android系統(tǒng)提供了兩個(gè)用于操作Uri的工具類,分別為UriMatcher和ContentUris 痰娱。掌握它們的使用弃榨,會(huì)便于我們的開(kāi)發(fā)工作。
UriMatcher
UriMatcher類用于匹配Uri梨睁,它的用法如下:
-
首先第一步把你需要匹配Uri路徑全部給注冊(cè)上
如下://常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼 UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配content://com.cfox.contentprovid.PersonProvider/person路徑鲸睛,返回匹配碼為1 sMatcher.addURI("com.cfox.contentprovid.PersonProvider", "person", 1);//添加需要匹配uri,如果匹配就會(huì)返回匹配碼 //如果match()方法匹配content://com.cfox.contentprovid.PersonProvider/person/230路徑坡贺,返回匹配碼為2 sMatcher.addURI("com.cfox.contentprovid.PersonProvider", "person/#", 2);//#號(hào)為通配符 switch (sMatcher.match(Uri.parse("content://com.cfox.contentprovid.PersonProvider/person/10"))) { case 1 break; case 2 break; default://不匹配 }
注冊(cè)完需要匹配的Uri后官辈,就可以使用sMatcher.match(uri)
方法對(duì)輸入的Uri進(jìn)行匹配。如果匹配就返回匹配碼遍坟,匹配碼是調(diào)用 addURI()
方法傳入的第三個(gè)參數(shù)拳亿,假設(shè)匹配content://com.cfox.contentprovid.PersonProvider
路徑,返回的匹配碼為1愿伴。
ContentUris使用介紹
ContentUris類用于操作Uri路徑后面的ID部分肺魁,它有兩個(gè)比較實(shí)用的方法:
-
withAppendedId(uri, id)用于為路徑加上ID部分:
Uri uri = Uri.parse("content://com.cfox.contentprovid.PersonProvider/person") Uri resultUri = ContentUris.withAppendedId(uri, 10); //生成后的Uri為:content://com.cfox.contentprovid.PersonProvider/person/10
-
parseId(uri)方法用于從路徑中獲取ID部分:
Uri uri = Uri.parse("content://com.cfox.contentprovid.PersonProvider/person/10") long personid = ContentUris.parseId(uri);//獲取的結(jié)果為:10
三、ContentProvider(內(nèi)容提供者)共享數(shù)據(jù)
ContentProvider在android中的作用是對(duì)外共享數(shù)據(jù)隔节,可以通過(guò)ContentProvider把應(yīng)用中的數(shù)據(jù)共享給其他應(yīng)用訪問(wèn)鹅经,其他應(yīng)用可以通過(guò)ContentProvider對(duì)你應(yīng)用中的數(shù)據(jù)進(jìn)行增刪改查胡桨。關(guān)于數(shù)據(jù)共享,以前我們學(xué)習(xí)過(guò)文件操作模式瞬雹,知道通過(guò)指定文件的操作模式為Context.MODE_WORLD_READABLE或Context.MODE_WORLD_WRITEABLE同樣也可以對(duì)外共享數(shù)據(jù)昧谊。那么,這里為何要使用ContentProvider對(duì)外共享數(shù)據(jù)呢酗捌?是這樣的呢诬,如果采用文件操作模式對(duì)外共享數(shù)據(jù),數(shù)據(jù)的訪問(wèn)方式會(huì)因數(shù)據(jù)存儲(chǔ)的方式而不同胖缤,導(dǎo)致數(shù)據(jù)的訪問(wèn)方式無(wú)法統(tǒng)一尚镰,如:采用xml文件對(duì)外共享數(shù) 據(jù),需要進(jìn)行xml解析才能讀取數(shù)據(jù)哪廓;采用sharedpreferences共享數(shù)據(jù)狗唉,需要使用sharedpreferences API讀取數(shù)據(jù)。使用ContentProvider對(duì)外共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)的訪問(wèn)方式涡真。
ContentProvider對(duì)外共享數(shù)
第一步需要繼承ContentProvider并重寫下面方法:
public class BaseContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}
ContentProvider類主要方法的作用:
- public boolean onCreate():該方法在ContentProvider創(chuàng)建后就會(huì)被調(diào)用分俯,應(yīng)用程序主線程上的所有已注冊(cè)內(nèi)容提供程序都會(huì)調(diào)用此方法。
- public Uri insert(Uri uri, ContentValues values):該方法用于供外部應(yīng)用往ContentProvider添加數(shù)據(jù)哆料。
- public int delete(Uri uri, String selection, String[] selectionArgs):該方法用于供外部應(yīng)用從ContentProvider刪除數(shù)據(jù)缸剪。
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用于供外部應(yīng)用更新ContentProvider中的數(shù)據(jù)。
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用于供外部應(yīng)用從ContentProvider中獲取數(shù)據(jù)东亦。
- public String getType(Uri uri):該方法用于返回當(dāng)前Url所代表數(shù)據(jù)的MIME類型杏节。
如果操作的數(shù)據(jù)屬于集合類型,那么MIME
類型字符串應(yīng)該以vnd.android.cursor.dir/
開(kāi)頭典阵。
例如:要得到所有person記錄的Uri為content://com.cfox.contentprovid.PersonProvider/person
那么返回的MIME類型字符串應(yīng)該為:"vnd.android.cursor.dir/person"
如果要操作的數(shù)據(jù)屬于非集合類型數(shù)據(jù)奋渔,那么MIME類型字符串應(yīng)該以vnd.android.cursor.item/開(kāi)頭
例如:得到id為10的person記錄,Uri為content://com.cfox.contentprovid.PersonProvider/person/10
那么返回的MIME類型字符串為:"vnd.android.cursor.item/person"
public String getType(Uri uri) {
UriMatcher uriMatcher = getUriMatcher();
int match = uriMatcher.match(uri);
switch (match) {
case ITEMS:
return "vnd.android.cursor.dir/" + person;
case ITEMS_ID:
return "vnd.android.cursor.item/" + person;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
第二步需要在AndroidManifest.xml使用對(duì)該ContentProvider進(jìn)行配置壮啊,為了能讓其他應(yīng)用找到該ContentProvider 嫉鲸,ContentProvider采用了authorities(主機(jī)名/域名)對(duì)它進(jìn)行唯一標(biāo)識(shí),你可以把ContentProvider看作是一個(gè)網(wǎng) 站(想想他巨,網(wǎng)站也是提供數(shù)據(jù)者)充坑,authorities 就是他的域名:
<provider
android:exported="true"
android:name="com.example.contentprovideranddb.ContentProvider.PersonProvider"
android:authorities="com.cfox.contentprovid.PersonProvider" />
四、使用ContentResolver操作ContentProvider中的數(shù)據(jù)
當(dāng)外部應(yīng)用需要對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行添加染突、刪除、修改和查詢操作時(shí)辈灼,可以使用ContentResolver 類來(lái)完成份企,要獲取ContentResolver 對(duì)象,可以使用Activity提供的getContentResolver()方法巡莹。 ContentResolver 類提供了與ContentProvider類相同簽名的四個(gè)方法:
public Uri insert(Uri uri, ContentValues values):該方法用于往ContentProvider添加數(shù)據(jù)司志。
public int delete(Uri uri, String selection, String[] selectionArgs):該方法用于從ContentProvider刪除數(shù)據(jù)甜紫。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用于更新ContentProvider中的數(shù)據(jù)。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用于從ContentProvider中獲取數(shù)據(jù)骂远。
這些方法的第一個(gè)參數(shù)為Uri囚霸,代表要操作的ContentProvider
和對(duì)其中的什么數(shù)據(jù)進(jìn)行操作, 例如 Uri是:Uri.parse("content://com.cfox.contentprovid.PersonProvider/person /10")
激才,那么將會(huì)對(duì)主機(jī)名為com.cfox.contentprovid.PersonProvider
的ContentProvider
進(jìn)行操作拓型,操作的數(shù) 據(jù)為person
表中id為10的記錄。 使用ContentResolver
對(duì)ContentProvider
中的數(shù)據(jù)進(jìn)行添加瘸恼、刪除劣挫、修改和查詢操作。
五东帅、監(jiān)聽(tīng)ContentProvider中數(shù)據(jù)的變化
如果ContentProvider
的訪問(wèn)者需要知道ContentProvider
中的數(shù)據(jù)發(fā)生變化压固,可以在ContentProvider
發(fā)生數(shù)據(jù)變化時(shí)調(diào)用getContentResolver().notifyChange(uri, null)
來(lái)通知注冊(cè)在此URI上的訪問(wèn)者,例子如下:
public class BaseContentProvider extends ContentProvider {
略.........
@Override
public Uri insert(Uri uri, ContentValues values) {
//添加數(shù)據(jù)變化通知
getContext().getContentResolver().notifyChange(uri, null);
return 返回一個(gè)Uri;
}
略........
}
如果ContentProvider
的訪問(wèn)者需要得到數(shù)據(jù)變化通知靠闭,必須使用ContentObserver
對(duì)數(shù)據(jù)(數(shù)據(jù)采用uri描述)進(jìn)行監(jiān)聽(tīng)帐我,當(dāng)監(jiān)聽(tīng)到數(shù)據(jù)變化通知時(shí),系統(tǒng)就會(huì)調(diào)用ContentObserver
的onChange()
方法:
public class MainActivity extends Activity {
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.getContentResolver().registerContentObserver(PersonProvider.uri, false, new MyObserver(mHandler));
}
public class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
//數(shù)據(jù)改變時(shí)調(diào)用
System.out.println("changing ------>");
}
}
}
六愧膀、ContentProvider 進(jìn)行批量操作
-
批量插入
在ContentProvider
中有特定的方法進(jìn)行批量插入bulkInsert
焚刚, 在ContentProvider
中從寫這個(gè)方法就可以實(shí)現(xiàn)批量插入的功能。下面來(lái)看一下扇调, 在實(shí)際開(kāi)發(fā)中的一種應(yīng)用矿咕。@Override public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) { int result; synchronized (this) { SQLiteDatabase db = mDBHelper.getWritableDatabase(); try { db.beginTransaction(); result = super.bulkInsert(uri, values); db.setTransactionSuccessful(); }finally { db.endTransaction(); } } return result; }
從上面代碼中可以看出,是為了使用事務(wù)批量插入數(shù)據(jù)提高插入效率狼钮。代碼很簡(jiǎn)單碳柱,不詳細(xì)介紹,這里說(shuō)一下
super.bulkInsert(uri, values);
這個(gè)行代碼熬芜, 下面看一下ContentProvider
類中是怎么實(shí)現(xiàn)的莲镣。public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) { int numValues = values.length; for (int i = 0; i < numValues; i++) { insert(uri, values[i]); } return numValues; }
看到
insert
相信很多人,就明白了涎拉,這里是遍歷ContentValues
中的每一個(gè)value 瑞侮, 最后還是通過(guò)insert
方法進(jìn)行操作。調(diào)用方法
通過(guò)ContentResolver 中bulkInsert
方法進(jìn)行批量操作:ContentResolver mcr = getContentResolver(); ---- ContentValues value1 = new ContentValues(); ContentValues value2 = new ContentValues(); ContentValues value3 = new ContentValues(); ContentValues[] contentValues = {value1, value2, value3}; int num = mcr.bulkInsert(mUri, contentValues);
-
批量操作
在ContentProvider中提供了一個(gè)功能更加豐富的批量操作方法applyBatch
鼓拧,使用這個(gè)可以進(jìn)行增半火、刪、 改季俩、 批量操作钮糖。還是先從一個(gè)使用例子開(kāi)始。@Override public ContentProviderResult[] applyBatch(@NonNull ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { ContentProviderResult[] results; synchronized (this) { SQLiteDatabase db = mDBHelper.getWritableDatabase(); try { db.beginTransaction(); results = super.applyBatch(operations); db.setTransactionSuccessful(); }finally { db.endTransaction(); } } return results; }
看了上面代碼和
批量插入
有些類似酌住,在這些代碼中要注意兩段代碼店归,ContentProviderOperation
和super.applyBatch(operations);
下面先來(lái)看看如何使用:
private static final String AUTHORITY = "com.cfox.contentprovid.PersonProvider"; ---- ContentResolver mcr = getContentResolver(); ---- ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); ContentValues values = new ContentValues(); operations.add(ContentProviderOperation.newInsert(mUri).withValues(values).build()); ContentValues values = new ContentValues(); operations.add(ContentProviderOperation.newUpdate(mUri) .withSelection("name = ?" , new String[]{"xxx"}) .withValues(values).build()); operations.add(ContentProviderOperation.newDelete(mUri) .withSelection("name = ?" , new String[]{"xxx"}).build()); try { mcr.applyBatch(AUTHORITY, operations); } catch (OperationApplicationException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); }
上面代碼不講解阎抒,下面通過(guò)源碼介紹一下在
ContentProvider
中是怎么進(jìn)行批量操作的。
先看一下ContentProviderOperation
中的newInsert
消痛、newUpdate
且叁、newDelete
三個(gè)方法實(shí)現(xiàn):public static Builder newInsert(Uri uri) { return new Builder(TYPE_INSERT, uri); } public static Builder newUpdate(Uri uri) { return new Builder(TYPE_UPDATE, uri); } public static Builder newDelete(Uri uri) { return new Builder(TYPE_DELETE, uri); }
三個(gè)方法都是創(chuàng)建了一個(gè)
Builder
實(shí)例,返回的也是Builder
對(duì)象而不是ContentProviderOperation
秩伞,不同的是傳入的type
不同逞带。那么在什么時(shí)候創(chuàng)建ContentProviderOperation
呢?在我們調(diào)用Builder
實(shí)例中的build()
方法是創(chuàng)建稠歉。下面來(lái)看一下具體代碼:public static class Builder { private final int mType; .... //省略部分代碼 private Builder(int type, Uri uri) { if (uri == null) { throw new IllegalArgumentException("uri must not be null"); } mType = type; mUri = uri; } .... //省略部分代碼 }
在
build
的時(shí)候?qū)?code>mType設(shè)置給ContentProviderOperation
中的mType
.所以才有下面使用mType
判斷是什么操作掰担。在看一下ContentProvider 中
applyBatch
方法實(shí)現(xiàn):public @NonNull ContentProviderResult[] applyBatch( @NonNull ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { final int numOperations = operations.size(); final ContentProviderResult[] results = new ContentProviderResult[numOperations]; for (int i = 0; i < numOperations; i++) { results[i] = operations.get(i).apply(this, results, i); } return results; }
上面代碼就是遍歷出
list
中的ContentProviderOperation
然后調(diào)用apply
方法,但是怒炸,到這里要注意apply
方法中有一個(gè)參數(shù)是this
带饱。繼續(xù)查看ContentProviderOperation
中apply
方法實(shí)現(xiàn):public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs, int numBackRefs) throws OperationApplicationException { ContentValues values = resolveValueBackReferences(backRefs, numBackRefs); String[] selectionArgs = resolveSelectionArgsBackReferences(backRefs, numBackRefs); if (mType == TYPE_INSERT) { Uri newUri = provider.insert(mUri, values); if (newUri == null) { throw new OperationApplicationException("insert failed"); } return new ContentProviderResult(newUri); } int numRows; if (mType == TYPE_DELETE) { numRows = provider.delete(mUri, mSelection, selectionArgs); } else if (mType == TYPE_UPDATE) { numRows = provider.update(mUri, values, mSelection, selectionArgs); } else if (mType == TYPE_ASSERT) { .... //省略部分代碼, 如果感興趣阅羹,自己閱讀研究 } else { Log.e(TAG, this.toString()); throw new IllegalStateException("bad type, " + mType); } if (mExpectedCount != null && mExpectedCount != numRows) { Log.e(TAG, this.toString()); throw new OperationApplicationException("wrong number of rows: " + numRows); } return new ContentProviderResult(numRows); }
看到這里勺疼,就會(huì)恍然大悟,原來(lái)是在這里通過(guò)
mType
這個(gè)屬性捏鱼,判斷增执庐、刪、改的导梆,讓后在通過(guò)傳入的ContentProvider
調(diào)用繼承ContentProvider
實(shí)現(xiàn)的insert
轨淌、update
、delete
方法看尼。
七递鹉、ContentProvider call 方法
先看一個(gè)使用例子:
ContentProvider 實(shí)現(xiàn):
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
extras.putString("data", "this is data");
return extras;
}
在activity 中調(diào)用call 實(shí)現(xiàn):
ContentResolver mcr = getContentResolver();
----
Bundle bundleArg = new Bundle();
bundleArg.putString("good", "hello");
Bundle bundle = mcr.call(mUri, "callMethod","call,,,,,,",bundleArg);
Log.d(TAG, "callMethod: data:" + bundle.get("data"));
調(diào)用和被調(diào)用參數(shù)都是相同的,注意:所有參數(shù)不可為NULL
藏斩, 可以使用這個(gè)方法使用Bundle
進(jìn)行數(shù)據(jù)交互躏结。
八、ContentProvider 文件共享
在ContentProvider
中用于共享大的文件的時(shí)候比較多狰域。文件會(huì)以流的形式傳遞媳拴。
下面是一個(gè)簡(jiǎn)單的使用例子:
ContentProvider
中示例:
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
String basePath = Environment.getExternalStorageDirectory().getPath() + "/aaa.pdf";
File file = new File(basePath);
ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
return descriptor;
}
activity 中調(diào)用示例:
Uri mUri = "";
----
ContentResolver mcr = getContentResolver();
----
String basePath = Environment.getExternalStorageDirectory().getPath() + "/bb.pdf";
File file = new File(basePath);
if (!file.isFile()) {
try {
boolean b = file.createNewFile();
Log.d(TAG, "AssetFile: b:" + b);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
AssetFileDescriptor descriptor = mcr.openAssetFileDescriptor(mUri, "r");
InputStream in = descriptor.createInputStream();
OutputStream out = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0 , len);
}
out.flush();
in.close();
out.close();
}catch (Exception e) {
e.printStackTrace();
}finally {
Log.d(TAG, "AssetFile: successs....");
}
上面代碼不解釋了,寫個(gè)demo體會(huì)一下兆览,很簡(jiǎn)單的屈溉, 這篇文章只是引路,告訴你ContentProvider
中有這些東西拓颓,具體在項(xiàng)目中如何使用语婴,還要結(jié)合實(shí)際場(chǎng)景。
九驶睦、幾點(diǎn)注意
- 不要在UI線程中調(diào)用砰左, 容易出現(xiàn)ANR。
-
ContentProvider
中onCreate
在運(yùn)行進(jìn)程的主線程中執(zhí)行场航。如果``ContentProvider和應(yīng)用運(yùn)行在同一進(jìn)程缠导,所以盡量不要在
onCreate中執(zhí)行耗時(shí)的操作或者不要做任何事情,如果在
onCreate`中執(zhí)行耗時(shí)的代碼溉痢,會(huì)影響應(yīng)用啟動(dòng)速度僻造。 - 如果
ContentProvider
和調(diào)用者在同一個(gè)進(jìn)程,則ContentProvider
和調(diào)用者在同一個(gè)線程孩饼。 - 如果
ContentProvider
和調(diào)用者不在同一個(gè)進(jìn)程髓削,onCreate
在進(jìn)程的主線程中執(zhí)行,insert
镀娶、update
立膛、delete
、query
梯码、call
等在同一個(gè)線程中執(zhí)行(非主線程)宝泵。
附:
在android4.2 在使用到 ContentProvider 的時(shí)候遇到的問(wèn)題,報(bào)錯(cuò): Permission Denial: opening provider uid=10033) .... that is not exported from uid 10036
在AndroidManifest.xml
中 android:exported
屬性轩娶,這個(gè)屬性用于指示該服務(wù)是否能被其他程序應(yīng)用組件調(diào)用或跟他交互儿奶; 取值為(true | false),如果設(shè)置成true鳄抒,則能夠被調(diào)用或交互闯捎,否則不能;設(shè)置為false時(shí)许溅,只有同一個(gè)應(yīng)用程序的組件或帶有相同用戶ID的應(yīng)用程序才能啟動(dòng)或綁定該服務(wù)瓤鼻。
<provider
android:exported="true"
android:name="com.example.contentprovideranddb.ContentProvider.PersonProvider"
android:authorities="com.cfox.contentprovid.PersonProvider" />
- 重要:它的默認(rèn)值是依賴于該服務(wù)所包含的過(guò)濾器
- 如果沒(méi)有過(guò)濾器則意味著該服務(wù)只能通過(guò)指定明確的類名來(lái)調(diào)用,也就是說(shuō)該服務(wù)只能在應(yīng)用程序內(nèi)部使用(因?yàn)槠渌獠渴褂谜卟粫?huì)知道該服務(wù)的類名)闹司,此時(shí)它的默認(rèn)值是false
- 如果至少包含了一個(gè)過(guò)濾器娱仔,則意味著該服務(wù)可以給外部的其他應(yīng)用提供服務(wù),因此默認(rèn)值是true游桩。
本文Uri 部分參考 :http://blog.sina.com.cn/s/blog_9f233c070101euqx.html
注:以上內(nèi)容牲迫,如有不對(duì)之處請(qǐng)及時(shí)指出,相互交流學(xué)習(xí)借卧。