文档章节

Android四大组件之一:ContentProvider

linin630
 linin630
发布于 2015/01/24 16:47
字数 1387
阅读 233
收藏 1

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

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

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

© 著作权归作者所有

linin630

linin630

粉丝 4
博文 34
码字总数 22734
作品 0
珠海
程序员
私信 提问
ContentProvider和数据库的区别

大家好,今天我们来讲解ContentProvider和数据库的区别是他们之间的联系. 四大组件之一 1.ContentProvider是如何实现数据共享的? 1.在Android中,为了把自己程序的数据(一般是数据库)提供给其他...

天王盖地虎626
06/17
33
0
Android系统中的进程管理:进程的创建

对于操作系统来说,进程管理是其最重要的职责之一。 考虑到这部分的内容较多,因此会拆分成几篇文章来讲解。 本文是进程管理系统文章的第一篇,会讲解Android系统中的进程创建。 本文适合And...

paulquei
09/29
0
0
Android 四大组件的工作过程

导语 本章的意义在于加深对四大组件工作方式的认识,有助于加深对Android整体的体系结构的认识。很多情况下,只有对Android的体系结构有一定认识,在实际开发中才能写出优秀的代码。 读者对四...

一个有故事的程序员
03/20
0
0
通读《疯狂Android讲义》笔记 01 ___Android基础篇

文 | 莫若吻 注: 1.本文内容参考 李刚的《疯狂Android讲义》一书。 2.此书适合有一定Java基础、初学Android的同学阅读与学习。我最近想巩固下Android基础知识就来拜读一下此书。 3.本文笔记...

莫若吻
2017/11/06
0
0
[武汉]android求实习,求试用

熟悉Android四大组件Activity、ContentProvider、Service、BroadcastReceiver的生命周期及使用方法 熟悉Android下的Socket网络编程、HTTP协议、XML、JSON解析 熟悉使用aidl实现进程间的通信以...

liu30506
2013/03/22
457
7

没有更多内容

加载失败,请刷新页面

加载更多

x002-语言元素

变量命令规则 硬性规则: 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。 大小写敏感(大写的a和小写的A是两个不同的变量)。 不要跟关键字(有特殊...

伟大源于勇敢的开始
今天
4
0
nginx反向代理配置

nginx配置文件位置/usr/local/nginx/conf/nginx.conf 配置文件修改: # cd /usr/local/nginx/conf # vim nginx.conf server {listen 80;server_name localhost;#charset k......

行者终成事
今天
5
0
OSChina 周日乱弹 —— 这是假的,和我之前的不一样

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐:《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
8
0
Rust学习笔记一 数据类型

写在前面 我也不是什么特别厉害的大牛,学历也很低,只是对一些新语言比较感兴趣,接触过的语言不算多也不算少,大部分也都浅尝辄止,所以理解上可能会有一些偏差。 自学了Java、Kotlin、Python、...

MusiCodeXY
今天
5
0
Java 脚本引擎入门

Java Script Engine Java 脚本引擎可以将脚本嵌入Java代码中,可以自定义和扩展Java应用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎,支持ECMAScript 5,但后期还可能会换...

阿提说说
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部