您的位置:首页 > 移动开发 > Android开发

Android基础知识总结---四大组件之一ContentProvider(一)

2016-07-23 23:46 561 查看

一、ContentProvider的简介

1.当系统部署多个Android应用之后,有时候就需要在不同的应用之间共享数据,比如现在有一个短信接收应用,用户想把接收到的陌生短信的发信人添加到联系人管理应用中,就需要不同应用之间共享数据。对于这种需要在不同应用之间共享数据的需求,可以让一个应用程序直接去操作另外一个应用程序所记录的数据,比如可以操作它所记录的SharedPreferences,文件或数据库等。但这种方式显得太杂乱了。不同应用程序记录数据的方式差别很大,这种方式不利于应用程序之间进行数据交换。为了在不同应用程序之间交换数据,Android提供了不同应用程序之间进行数据交换的标准API:ContentProvider,它也是Android中四大组件之一,当然ContentProvider既然作为Android应用的四大组件之一,那么就需要在AndroidManifest.xml文件中进行配置。当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可以通过提供ContentProvider来实现,其他应用程序就可通过ContentResolver来操作ContentProvider暴露的数据,包括增加数据,删除数据,修改数据,查询数据等。同时Android已经为常见的一些数据提供了默认的ContentProvider.比如说:短信,通讯录,通话记录,多媒体等。

二、开发自己应用程序的ContentProvider

第一步:定义自己的ContentProvider类,该类继承ContentProvider基类

第二步:暴露需要提供的数据:

重写onCreate():该方法在ContentProvider创建后被调用

重写getType():该方法用于返回当前Uri所代表的数据的MIME类型,

如果该Uri对应的数据可能包括多条记录,那么MIME类型字符串应用以vnd.android.cursor.dir/开始

如果该Uri对应的数据只包括一条记录,那么MIME类型字符串应用以vnd.android.cursor.item/开始

重写insert(Uri,ContentValue values):根据Uri插入values对应的数据

重写delete(Uri,String selection,String[] selectArgs):根据Uri删除select条件匹配的全部记录

重写update():根据Uri修改select条件所匹配的全部记录

重写query():根据Uri查询出select条件所匹配的全部记录

注意:重写的这些方法并不是给该应用本身调用的,而是供其他应用通过ContentResolver来调用。

第三步:在AndroidManifest.xml文件中注册该ContentProvider,指定android:authorities属性

三、ContentProvider中一些属性的含义

1.Uri:用于表示这个ContentProvider所提供的数据

Uri:统一资源标识符

–URL:统一资源定位符

–URN:统一资源命名符

如:http://www.baidu.com/index.html
http:// 是URL的协议部分,是固定的

www.baidu.com是域名部分,是固定的

index.html是网站资源部分,是动态的

而ContentProvider提供的Uri,例如:

如:content://com.ecjtu.dictprovider/users

content://是Uri的协议部分,暴露ContentProvider,访问contentProvider的协议默认是content://,这个部分是固定的。

com.ecjtu.dictprovider:是ContentProvider的authority。系统就是由这个部分找到操作哪个ContentProvider.

如果需要访问指定的ContentProvider,这个部分也是固定的。

users:是资源部分,当访问者需要访问不同资源时,这个部分是动态改变的。

Uri提供了parse()静态方法,可以将字符串转换为Uri:

Uri uri = Uri.parse(“content://com.ecjtu.dictprovider/user/2”);

2、ContentResolver

通过ContentResolver来操作ContentProvider所暴露的数据

使用步骤:

第一步:通过Context中获取ContentResolver象:getContentResolver()

第二步:调用ContentResolver中相应的方法:insert,delete,update,query

四、实现原理

A应用:通过ContentProvider提供数据

^

|

|

Uri

^

|

|

B应用: 通过ContentResolver获取数据

注意:

当B应用调用ContentResolver的insert方法时,实际上相当于调用了该Uri对应的ContentProvider(属于A应用)的insert方法。

当B应用调用ContentResolver的update方法时,实际上相当于调用了该Uri对应的ContentProvider(属于A应用)的update方法。

在A应用里编写ContentProvider

1)重写onCreate(),getType(),insert(),delete(),update(),query()

2)在Manifest中配置标签

android:name provider的全类名

android:authorities 为该Provider设置访问该URI的Host部分

android:exported 设置该Provider可以被其他应用程序访问

在B应用

1)调用getContentResolver,获取resolver对象

2)调用insert(),delete(),update(),query(),传入URI实现数据访问

五、操作系统的ContentProvider提供的数据:

a)全部短信的Uri为:content://sms/

查询出所有的短信:

Cursor cursor=cr.query(“content://sms/”, new String[]{“_id”,”address”,”body”,”date”}, null, null,null);

然后在ListView中显示出来

注意需要添加权限:android.permission.READ_SMS

上面只是获取的部分内容:完整的内容可以在数据库表中看到:

通讯录数据库是:/data/data/com.android.providers.contacts/databases/contacts2.db

短信数据库是:/data/data/com.android.providers.telephony/databases/mmssms.db

b)自己编写发送短信的应用并将短信写入到数据库中

短信管理器SmsManager(android.telephony.SmsManager)

SmsManager是Android中提供的另一个非常常见的服务。

获取SmsManager的方式:manager = SmsManager.getDefault();

SmsManager提供了系列sendXxxMessage()方法用于发送短信,不过在实际应用来看,短信都是普通的文本内容,也就是调用sendTextMessage()方法进行发送即可。

sendTextMessage(String destinationAddress, String scAddress, String text,

PendingIntent sentIntent, PendingIntent deliveryIntent)

第一个参数:收件人的手机号码

第二个参数:短信服务中心,如果为null,就是用当前默认的短信服务中心

第三个参数:短信内容

第四个参数:如果 sentIntent不为空,当短信发出时,成功或者失败的信息报告是通过sentIntent来广播给接收器接收。

接收的方式:在接收器中getResultCode()获取,这个PendingIntent被广播出去,成功的结果代码是Activity.RESULT_OK,或者下面这些错误之一 :

RESULT_ERROR_GENERIC_FAILURE

RESULT_ERROR_RADIO_OFF

RESULT_ERROR_NULL_PDU

对于 RESULT_ERROR_GENERIC_FAILURE,这个sentIntent可能包括额外的”errorCode”,包含一些具体有用的信息帮助检查 。基于SMS控制的全部程序去检查 sentIntent.

如果 sentIntent 为空,如果该参数为空,则发信程序会被所有未知的应用程序检查一遍,这样会导致发送的时间延长

第五个参数:如果不为null,当这个短信发送到接收者那里时,这个PendtingIntent会被广播,状态报告生成的pdu数据(指对等层次之间传递的数据单位)会拓展到数据(”pdu”)

c)写入到数据库

Uri uri= Uri.parse(“content://sms/sent”);

ContentValues contentValues=new ContentValues();

contentValues.put(“address”,address);

contentValues.put(“body”,body);

contentValues.put(“date”, System.currentTimeMillis()); //创建时间

contentValues.put(“read”, 0); //0:未读;1:已读

contentValues.put(“type”, 2); //1:接收;2:发送

cr.insert(uri,contentValues);

注意:需要添加权限

六、操作系统的ContentProvider

Android系统本身提供了大量的ContentProvider,例如联系人信息,系统的多媒体信息等。开发者自己开发Android应用也可以通过ContentResolver来调用系统的ContentProvider提供的数据。为了操作系统的ContentProvider,需要了解ContentProvider的Uri,以及该ContentProvider所操作的数据列的列名。

a)使用ContentProvider管理联系人

ContactsContract.Contacts.CONTENT_URI: 管理联系人的Uri

ContactsContract.CommonDataKinds.Phone.CONTENT_URI: 管理联系人的电话的URI

ContactsContract.CommonDataKinds.Email.CONTENT_URI: 管理联系人的Email的URI

例:查看手机SD卡中的音乐媒体文件

通过Android ContentResolver提供的查询方法:

Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

各参数的含义:

Uri:指明要查询的数据库名称加上表的名称,从MediaStore中我们可以找到相应信息的参数。

Projection: 指定查询数据库表中的哪几列,返回的游标中将包括相应的信息。Null则返回所有信息。

selection: 指定查询条件

selectionArgs:填充通配符,如果查询条件里面没有通配符则可以为null

SortOrder:指定查询结果的排列顺序

下面的命令将返回所有在外部存储卡上的音乐文件的信息:

Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);

得到cursor后,我们可以调用Cursor的相关方法具体的音乐信息:

歌曲ID:MediaStore.Audio.Media._ID

Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));

歌曲的名称:MediaStore.Audio.Media.TITLE

String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));

歌曲的专辑名:MediaStore.Audio.Media.ALBUM

String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));

歌曲的艺术家:MediaStore.Audio.Media.ARTIST

String artist = cursor.getString(cursor .getColumnIndex(MediaStore.Audio.Media.ARTIST));

歌曲的歌手名:MediaStore.Audio.Media.ARTIST

String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));

歌曲文件的路径:MediaStore.Audio.Media.DATA

String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));

歌曲的总播放时长:MediaStore.Audio.Media.DURATION

Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));

歌曲文件的大小:MediaStore.Audio.Media.SIZE

Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));

歌曲是否为音乐:MediaStore.Audio.Media.IS_MUSIC

int isMusic = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC));

七、ContentProvider续:

1.UriMatcher和ContentUris的使用:

为了确定该ContentProvider实际能处理的Uri,以及确定每个方法中Uri参数所操作的数据,

Android系统提供了UriMatcher工具类。

a)UriMatcher工具类提供了如下两个主要方法:

addURI(String authority,String path,int code):

该方法用于向UriMatcher对象注册Uri.其中authority和path组合成一个Uri,而code则代表该Uri对应的标识码。

int match(Uri uri):根据前面注册的Uri来判断指定Uri对应的标识码。如果找不到匹配的标识码,该方法返回-1.

比如:

UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);

matcher.addURI(“com.ecjtu.dictprovider”,”users”,1)

matcher.addURI(“com.ecjtu.dictprovider”,”user/#”,2)#号是通配符,上面的代码注册了两个Uri。

匹配标识符:

matcher.match(Uri.parse(“content://com.ecjtu.dictprovider/users”)//返回标识符1

matcher.match(Uri.parse(“content://com.ecjtu.dictprovider/user/2”)//返回标识符2

matcher.match(Uri.parse(“content://com.ecjtu.dictprovider/user/10”)//返回标识符2

至少需要为UriMatcher对象注册多少个Uri,取决于系统的业务需求。

对于content://com.ecjtu.dictprovider/users通常代表返回所有数据

对于content://com.ecjtu.dictprovider/user/2通常代表访问指定数据项,其中最后一个数值往往代表了该数据的ID。

b)ContentUris

它是一个操作Uri字符串的工具类。提供如下两个方法:

withAppendedId(uri,id)用于为路径后加上ID部分

如:Uri resultUri=ContentUris.withAppendedId(uri,2)

parseId(uri):用于从指定Uri中解析所包含的ID值

2.监听ContentProvider的数据改变—>ContentObserver

当ContentProvider将数据共享出来之后,ContentResolver会根据业务需要去主动查询ContentProvider所共享数据,在有些时候,应用程序需要实时监听ContentProvider所共享数据的改变,并随着ContentProvider的数据的改变而提供响应,这就需要利用ContentObserver了。前面介绍开发ContentProvider时,不管实现insert,delete,update方法中的哪一个,只要该方法导致了ContentProvider里的数据的改变,程序就会调用了如下代码:

getContext().getContentResolver().notifyChange(uri,null);

这行代码可用于通知所有注册在该Uri上的监听者,该ContentProvider所共享的数据发生了改变。监听ContentProvider数据改变的监听器需要继承ContentObserver类,并重写该基类的onChange()方法,当它所监听的ContentProvider的数据发生改变时,该onChange()方法将会被触发。为了监听指定的ContentProvider的数据变化,需要通过ContnetResolver向指定Uri注册ContentObserver监听器:

注册监听器:ContentResolver的registerContentObserver(Uri,boolean,ContentObserver)方法。

第一个参数:监听的Uri

第二个参数:如果该参数设为true,假如注册监听的uri为content://abc,那么Uri为content://abc/xyz,content://abc/xyz/foo的数据改变时也会触发该监听器。如果该参数设为false,假如注册监听的uri为content://abc,那么只有content://abc的数据发生改变时会触发该监听器。

第三个参数:监听器实例

3.自动朗读TTS

自动朗读可以对指定文本内容进行朗读,从而发生声音。这种自动朗读支持的英文名称为TextToSpeech,简称TTS.

创建TTS:TextToSpeech(Context,TextToSpeech.onOnitListener),

传入的监听器负责监听TextToSpeech的初始化结果。创建对象之后,setLanguage(Locale)设置TTS发声引擎使用的语言,国家选项。

speak(String text,int queueMode,HashMap):指定发音任务

queueMode:指定发音队列模式,该参数支持的值有:

TextToSpeech.QUEUE_FLUSH:会中断当前实例正在运行的任务

TextToSpeech.QUEUE_ADD:把新的发音任务添加到当前发音队列中。

shutdown()关闭TextToSpeech,释放资源
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息