一、ContentProvider是什麼?java
ContentProvider是安卓平臺中,在不一樣應用程序之間實現數據共享的一種機制。一個應用程序若是須要讓別的程序能夠操做本身的數據,便可採用這種機制。android
二、ContentProvider能作什麼事?sql
共享數據:好比短信應用就共享了全部短信的數據,咱們能夠用代碼操做這些數據,以下:數據庫
getContentResolver().query(Uri.parse("content://sms/inbox");
三、ContentProvider要怎麼用?ide
這裏以一個簡單的demo來演示用法。工具
(1)新建程序A,在程序A中新建一個類繼承ContentProviderspa
public class MyProvider extends ContentProvider{ static final String TABLE_NAME = "test"; static final String ID = "id"; static final String CONTENT = "content"; @Override public boolean onCreate() { SQL.addTable(TABLE_NAME, ID, CONTENT); SQL sql = SQL.init(getContext()); sql.createTable(); sql.insert(TABLE_NAME, "001", "NeiRon"); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQL sql = SQL.init(getContext()); Cursor c = sql.query(TABLE_NAME, new String[]{ID}, new String[]{"001"}); return c; } }
這個ContentProvider在初始化的時候新建了一個數據庫,而且新建了一張表,插入了一行數據;code
調用query查詢的時候我寫死了,直接查整張表;(懶)xml
SQL是我寫的一個數據庫工具類,比較懶就直接拖過來用了,不用在乎。
繼承
(2)在manifest中定義MyProvider
<provider android:name="com.example.testb.MyProvider" android:authorities="com.linin.test" android:exported="true" > </provider>
android:authorities的參數能夠本身定義,只是個標識而已。
注意:android:exported="true"的意思是容許其餘程序調用本程序的MyProvider,默認是false;網上不少教程都沒提到這個,緣由是在2.3以前的系統不添加也能被其餘程序調用,不知道爲何,反正我是被這個坑慘了!QAQ
(3)新建程序B,在程序B中查詢MyProvider共享的數據;
注意Uri的格式是:content://自定義的標識[/表名][/ID]
自定義標識其實就是程序A的android:authorities;
表名=數據庫表名;ID=_id參數;
(若是不太熟悉的,建議去百度一下)
注意:實際上只要自定義標識對上了,就能調用MyProvider的query方法,以後就根據傳過來的Uri進行後續的操做;我這個demo由於沒對Uri作任何操做,形同虛設,因此怎麼傳都無所謂(保證content://com.linin.test開頭就行);
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.text); ContentResolver cr = getContentResolver(); Uri uri = Uri.parse("content://com.linin.test"); Cursor c = cr.query(uri, null, null, null, null); if (c!=null&&c.moveToNext()) { tv.setText(c.getString(c.getColumnIndex(CONTENT))); } c.close(); c = null; }
運行結果:在程序B中獲取到了程序A共享的數據,並顯示出來,以下:
四、一些其餘的東西?
網上的一些教程有提到UriMatcher、ContentUris這兩個工具類,其實吧,這兩個類其實無關緊要,一個是爲了判斷查詢所有表數據仍是查詢單條數據,一個是拼接Uri的。好吧,對於習慣用正則又喜歡字符串+字符串拼接的我來講沒太必要,不過仍是瞭解一下吧。
(1)UriMatcher,從名字就能夠看出這個工具類其實就是用了正則來判斷的。用法以下,在ContentProvider中初始化:
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static{ uriMatcher.addURI("com.linin.test", "test", 0);//表明查詢整張test表 uriMatcher.addURI("com.linin.test", "test/#", 1);//表明查詢test表的單條數據 }
而後在getType中判斷Uri的數據類型:
public String getType(Uri uri) { Log.e("test","getType!!!"+uri.toString()); int witch = uriMatcher.match(uri); switch (witch) { case 0://查詢整張表 return "vnd.android.cursor.dir/test"; case 1://查詢單條數據 return "vnd.android.cursor.item/test"; } return null; }
那麼問題就來了:咱們何時要用到這個getType呢?
實際上,我在程序B中獲取到程序A的共享數據後,getType一次也沒被調用。
其實只要在程序B中把getContentResolver().getType(uri)打印出來就知道了,ContentResolver中的getType會根據傳入的Uri與每一個ContentProvider匹配,匹配後調用其getType獲取該數據類型。
那麼問題又來了:這樣作有什麼意義?
好吧其實意義不大。到這裏其實我已經醉了,網上的教程對getType的說法模糊不清,越看越亂。接下來我就以我本身的理解來介紹下getType吧!
看我寫的代碼就知道了,getType的做用只有一個,就是返回數據的類型,返回類型的做用固然也只有一個,用來判斷!
因而咱們能夠在query方法中這樣寫:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { String type = getType(uri); if (type.equals("vnd.android.cursor.dir/test")) { //多行數據類型 }else if (type.equals("vnd.android.cursor.item/test")) { //單行數據類型 } return c; }
做用很明顯了,就是用來判斷數據類型的(多行or單行)!
一些聰明的小夥伴可能發現了:那我直接把getType裏面的判斷搬出來不就好了?
嗯。。。確實在MyProvider裏面是能夠這樣寫,不過也得考慮其餘狀況,好比說在個人程序B中,若是不用getContentResolver().getType(uri)去獲取數據類型的話,那我就又要初始化一次UriMatcher了,畢竟UriMatcher的初始化是在程序A的MyProvider中完成的。
呼呼呼,總算強行解釋通了~~
(2)ContentUris,一個神奇的工具,他能夠作到這樣:
Uri uri = Uri.parse("content://com.linin.test/test"); Uri resultUri = ContentUris.withAppendedId(uri, 10); 結果: resultUri-->content://com.linin.test/test/10 等價於: Uri resultUri = Uri.parse("content://com.linin.test/test/10");
他也能夠作到這樣:
Uri uri = Uri.parse("content://com.linin.test/test/10"); long id = ContentUris.parseId(uri); 結果: id-->10
說實話,我不知道這個工具類有什麼存在的必要。。。瞭解了就行,用不用隨意吧。