Android四大组件之一:ContentProvider

1、ContentProvider是什么?

ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。

2、ContentProvider能做什么事?

共享数据:比如短信应用就共享了所有短信的数据,我们可以用代码操作这些数据,如下:

getContentResolver().query(Uri.parse("content://sms/inbox");

3、ContentProvider要怎么用?

这里以一个简单的demo来演示用法。

(1)新建程序A,在程序A中新建一个类继承ContentProvider

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在初始化的时候新建了一个数据库,并且新建了一张表,插入了一行数据;

调用query查询的时候我写死了,直接查整张表;(懒)

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共享的数据,并显示出来,如下:

Android四大组件之一:ContentProvider_第1张图片

4、一些其他的东西?

网上的一些教程有提到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

说实话,我不知道这个工具类有什么存在的必要。。。了解了就行,用不用随意吧。

你可能感兴趣的:(ContentProvider,urimatcher,getType,ContentUris)