一、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
说实话,我不知道这个工具类有什么存在的必要。。。了解了就行,用不用随意吧。