天天看点

Android 流媒体系列(一)Android   设置铃声分析  

代码其实没有几行,这里简单记录下学习的过程.

Android系统启动时会扫描系统与SD卡中的对媒体文件,分别存入数据库sqlite中,以contentProvider的形式对外提供服务

路径:/data/data/com.android.providers.media/databases/XXX...

Android 流媒体系列(一)Android   设置铃声分析  

可以看到有2个db文件, 一个是系统的,一个是sd卡里的

用SQLite Expert打开internal.db,部分截图如下:

Android 流媒体系列(一)Android   设置铃声分析  

这里面记录了音频audio、视频video、图片images的相关数据信息,我们以音频audio为例,蓝色部分audio_meta就是audio数据表,打开之后就可以看到详细信息了,里面列出了系统内部的所有音频文件,各个字段在android.provider.MediaStore中都定义有相应的常量,如id --- MediaStore.Audio.Media._ID.

而这里面有想说下这四个字段

Android 流媒体系列(一)Android   设置铃声分析  

含义在源码里都有说明,看了一遍数据,发现这四个字段同时有且仅有一个字段为1,也就是对于一个多媒体文件只能是这四种中的一种,默认为0,如果是某种类型,则android系统默认置为1,所以也就明白了为什么很多扫描系统通知或者来电铃声的示例代码中,都会有一个类似的条件语句:is_notification = 1.

如:

Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  

这里 is_notification != 0,效果是一样的,除非哪天google再定义个2, 3 ......

上面扯了些其他的,关于设置铃声的方法,系统提供了一个铃声管理器android.provider.RingtoneManager,其中提供了获取与设置铃声的API

如:Uri uri = RingtoneManager.getActualDefaultRingtoneUri(MediaActivity.this, RingtoneManager.TYPE_NOTIFICATION);可以获取到当前系统的通知铃声uri

第二个参数可以指定获取的铃声类型,还有其他的TYPE_RINGTONE,TYPE_ALARM, TYPE_ALL

设置铃声的API:

第二个参数同上,最后一个是指定一个新的Uri, 这里的data.get(position)就是在上面的扫描代码扫描出的所有通知铃声path路径中选泽一个,然后在解析成一个URI对象传入即可

那么android是如何获取指定类型的系统铃声呢?

这涉及到另一个类android.provider.Settings

相关源码如下:

Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  

settings.db结构如下:

Android 流媒体系列(一)Android   设置铃声分析  

上面示例中指定的TYPE_NOTIFICATION的数据如下(蓝色部分):

Android 流媒体系列(一)Android   设置铃声分析  

最后返回的就是file:///..........这个String数据,再转化成URI返回给调用者

OK,那么设置铃声的API, setAc.......执行的过程也类似:

Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  
Android 流媒体系列(一)Android   设置铃声分析  

最后总结下,从整个过程可以看到android系统的一些设计思想

1,设置铃声之前,要先知道有哪些系统铃声,所以需要扫描,android提供了xxx.media这个contentProvider为此服务,对应的数据库为internal.db/external-xx.db

2,拿到铃声,真正需要设置的时候,提供了Setting类管理这个过程,其对应的数据库为settings.db

  2.1 首先检查是否涉及到系统的一些安全设置参数,这里定义了Secure类来管理,如果涉及到系统安全,那么又分为两种情况:

    2.1.1 如果是查询,则操作secure 表查询

    2.1.2 如果是写操作,则直接return

  2.2 不涉及到系统安全,就属于正常设置,接着定义了System类管理

3,查询操作的实际操作类NameValueCache, 其中定义了

  缓存name/value键值对的集合,避免每次操作都去操作数据库

  可以由调用者指定的uri,便于根据uri决定去操作哪张表

以及写操作的NameValueTable类,因为写操作涉及到id, 所以继承了BaseColumns类

=========================================

=========================================以下是转载附带参考:

今天给大家讲android的多媒体数据库。MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去掉用那些封装好的接口就可以进行数据库的操作了。今天我就介绍一些这些接口的用法。 

    首先,要得到一个ContentResolver实例,ContentResolver可以这样获取,利用一个Activity或者Service的Context即可。如下所示: 

    ContentResolver mResolver = ctx.getContentResolver(); 

    上面的那个ctx的就是一个context,Activity.this就是那个Context,这个Context就相当于一个上下文环境。得到这个Context后就可以调用getContentResolver接口获取ContentResolver实例了。ContentResolver实例获得后,就可以进行各种查询,下面我就以音频数据库为例讲解增删改查的方法,视频和图像和音频非常类似。 

    在讲解各种查询之前,我给大家介绍下怎么看android都提供了哪些多媒体表。在adb shell中,找到/data/data/com.android.providers.media/databases/下,然后找到SD卡的数据库文件(一般是一个.db文件),然后输入命令sqlite3加上这个数据库的名字就可以查询android的多媒体数据库了。.table命令可以列出所有多媒体数据库的表,.scheme加上表名可以查询表中的所有列名。这里可以利用SQL语句来查看你想要的数据,记得最后一定要记住每条语句后面都加上分号。下面开始讲述怎么在这些表上进行增删改查。 

    查询,代码如下所示: 

    Cursor cursor = resolver.query(_uri, prjs, selections, selectArgs, order); 

    ContentResolver的query方法接受几个参数,参数意义如下: 

    Uri:这个Uri代表要查询的数据库名称加上表的名称。这个Uri一般都直接从MediaStore里取得,例如我要取所有歌的信息,就必须利用MediaStore.Audio.Media. EXTERNAL _CONTENT_URI这个Uri。专辑信息要利用MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI这个Uri来查询,其他查询也都类似。 

    Prjs:这个参数代表要从表中选择的列,用一个String数组来表示。 

     Selections:相当于SQL语句中的where子句,就是代表你的查询条件。 

    selectArgs:这个参数是说你的Selections里有?这个符号是,这里可以以实际值代替这个问号。如果Selections这个没有?的话,那么这个String数组可以为null。 

     Order:说明查询结果按什么来排序。 

    上面就是各个参数的意义,它返回的查询结果一个Cursor,这个Cursor就相当于数据库查询的中Result,用法和它差不多。 

------------------------------------------------------------------------------------------------------------------- 

    增加,代码如下所以: 

    ContentValues values = new ContentValues(); 

    values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,0); 

    resolver.insert(_uri, values); 

    这个insert传递的参数只有两个,一个是Uri(同查询那个Uri),另一个是ContentValues。这个ContentValuses对应于数据库的一行数据,只要用put方法把每个列的设置好之后,直接利用insert方法去插入就好了。 

    更新,代码如下: 

    ContentResolver resolver = ctx.getContentResolver(); 

    Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 

    values.put(MediaStore.Audio.Media.DATE_MODIFIED, sid); 

    resolver.update(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,values, where, selectionArgs); 

    上面update方法和查询还有增加里的参数都很类似,这里就不再重复叙述了,大家也可直接参考google的文档,那里也写的很清楚。 

    删除,代码如下: 

    nbsp;   resolver.delete(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,where, selectionArgs); 

    delete和更新的方法很类似 。