首页 > 其他分享 >Android ContentProvider详解

Android ContentProvider详解

时间:2023-05-21 22:32:09浏览次数:53  
标签:10 详解 Provider Android ContentProvider type


一.Android四大组件

Android四大组件是Activity, Service, Content Provider, Broadcast Receiver。

Activity作为程序界面,直接与用户交互

Service运行在后台,没有界面,完成特定的功能

ContentProvider维护应用数据,方便应用本身或其它应用访问

Broadcast Receiver提供异步广播消息接收机制,便于各应用/组件进行交互

 

通过AndroidManifest.xml,  可以看到一个应用使用了哪些组件:

 

Android <wbr>ContentProvider详解

   attribute的定义可以参考http://developer.android.com/guide/topics/manifest/manifest-intro.html

下面重点探讨Content Provider的实现和使用。

 

二. 什么是ContentProvider

Content Provider维护特定的应用数据,并可以让其它应用轻松访问该数据。对数据使

用者来说它是数据提供者。它提供统一的接口对数据进行操作,使用者不用关心数据到底是如何存储的以及数据类型到底是什么。也就是说,Content Provider作为数据提供者,提供了对外共享本地数据一种机制,使Android应用能方便地基于该机制进行数据访问。

为了便于管理和访问,每个Content Provider必须有唯一标示,用Uri表示。Uri类似http url, 构成如下:

    content://authority/path

所有Content Provider的Uri必须以content://开头,这是Android规定的。

是个字符串,它由开发者自己定义,用于来唯一标示一个ContentProvider。系统会根据这个标示查找ContentProvider。

也是字符串,表示要操作的数据。可根据自己的实现逻辑来指定:
content://contacts/people表示要操作ContentProvider为contacts下的people表

content://com.android.contacts/people/#表示要操作表people中特定id的行(记录)。

content://downloads/download/10/name表示要操作id为10的行的name字段。

content://downloads/download/*表示操作download表中的所有字段。

总之,#匹配一个数字字符串,*匹配一个文本字符串。

 

三.ContentProvider 的实现和使用

Android <wbr>ContentProvider详解

可以看出 , 实现一个自定义的Content Provider,要基于系统提供的基类ContentProvider,需要实现6个接口。大部分接口就是类似数据库的数据操作接口,实际上Content Provider是需要创建数据库并对数据库进行操作的。完成实现之后,在Androidmanifest.xml中声明自己的Content Provider以及与Provider相关的permission声明(可以没有permission定义)。例如:

Android <wbr>ContentProvider详解

    最后整个应用被编译成apk。安装之后,该应用里的contentProvider就可以被其它应用访问了。对于Provider使用者来说,  如果特定Provider有permission要求,则要在自己的Androidmanifest.xml中添加指定Permission引用, 如:

Android <wbr>ContentProvider详解

使用非常简单,Android提供了Context级别的ContentResolver对象来对Content Provider进行操作。正是因为有了ContentResolver, 使用者才不用关心Provider到底是哪个应用或哪个类实现的。只要知道它的uri就能访问。ContentResolver对象存在于每个Context中。几乎所有对象都有自己的Context。

Android ContentProvider详解_java_05


     有些情况下,Content Provider使用者想监听数据的变化,可以注册一个Observer:

 

Android <wbr>ContentProvider详解


四. ContentProvider内部机制


1.ContentProvider接口调用过程

依赖ContentResolver/ActivityThread/ActivityManagerService对外提供

服务。虽然ContentProvider的用法以及表现形式不是一个Service,实际上它可以看作是ActivityManagerService提供的一种服务, 它实现了IBinder接口。

首先调用者通过特定uri调用特定ContentProvider的接口函数,比如insert(),  此时ContentResolver会通过uri获取特定ContentProvider的实例,ActivityThread检查本地Cache,如果发现此ContentProvider已经被引用过,则直接直接取出ContentProvider返回给调用者。如果没有发现,由于ContentProvider可能已经被load了,可能还没有load;可能要创建Process,可能要检查permission,所以ActivityThread调用到ActivityManagerService来进行相关处理/检查。如果该Provider是Single Process,ActivityManagerService会为ContentProvider创建一个独立Process;如果是MultiProcess,说明每个调用者可以拥有独立的ContentProvider实例,于是ActivityManagerService只是返回ContentProvider的相关信息给ActivityThread,由ActivityThread负责ContentProvider的实例化,此时ContentProvider运行在调用者Process中。实例化后,IConentProvider会返回给调用者,通过该接口可以调用所需功能。

本地维护一个mProviderMap <ProviderName, ProviderRecord >,记录已被引用的ContentProvider,  同时使用引用计数mProviderRefCountMap <IBinder, ProviderRefCount>记录特定ContentProvider的引用情况。

Android <wbr>ContentProvider详解

 

2.ContentProvider实例创建过程

     ContentProvider实例的创建与multiprocess属性有关系(Androidmanifest.xml里指定),个人认为理解成多进程并不准确。应该理解为ContentProvider的多实例,不会存在多个ContentProvider进程的情况,ContentProvider 可能存在多个实例。

1) 对于android:multiprocess=true的ContentProvider,意味着可以多实例,那么由调用者在自己的进程空间实例化一个ContentProvider对象,此时定义ContentProvider的App可能并没有启动

Android <wbr>ContentProvider详解

 

注意:ContentProvider是否多实例,还得看contentProvider的uid与调用者的uid是否相同或contentProvider的uid是System user。具体逻辑是:

public boolean canRunHere(ProcessRecord app) {
        return (info.multiprocess || info.processName.equals(app.processName))
                && (uid == Process.SYSTEM_UID || uid == app.info.uid);
}

 

2)对于android:multiprocess=false(默认值)的ContentProvider,由系统把定义该ContentProvider的App启动起来(一个独立的Process)并实例化ContentProvider,这种ContentProvider只有一个实例,运行在自己App的Process中。所有调用者共享该ContentProvider实例,调用者与ContentProvider实例位于两个不同的Process

Android <wbr>ContentProvider详解

 

其中Process.start()->zygoteSendArgsAndGetPid()->ZygoteInit.runSelectLoopMode()

-> ZygoteConnection.runOnce() -> Zygote.forkAndSpecialize()->RuntimeInit.zygoteInit()

-> invokeStaticMain()->MethodAndArgsCaller.run()->Method.invokeNative

->ActivityThread.main(),这是通用的APK启动流程。

 

3)ContentProvider的加载/发布过程

   ContentProvider不能单独发布,总是被打包到某个Android应用(apk)里。APK被安装之后,实例化之后每个Android应用都有一个Application实例,每个Activity或Service有一个ApplicationContext实例。

应用程序的入口函数是ActivityThread.main(), 该函数不仅创建了ActivityThread实例以及消息循环机构,而且创建了ApplicationThread实例,通过此实例向Activity Manager

通过attachApplication()把自己的ApplicationThread实例告知AMS。

AMS根据thread信息更新进程记录(ProcessRecord)并调用thread的bindApplication()进行初始化工作并创建ApplicationContext和Application实例,然后安装package里声明的所有contentProvider。 主要过程如下:

Android <wbr>ContentProvider详解

AMS维护了很多信息,其中比较重要的有:

mProcessNames:      包名(processName)和进程信息(ProcessRecord)映射表

mProvidersByName:   Provider发布名和Provider信息(ContentProviderRecord)映射表

mProvidersByClass:  Provider类名和Provider信息(ContentProviderRecord)映射表

conProviders:属于ProcessRecord信息,特定Process正在使用的ContentProvider及其个数映射表

pubProviders:属于ProcessRecord信息,特定Process已经Published的Provider类名和Provider信息

映射表

ActivityThread维护了3个与ContentProvider相关的Map:

mProviderMap:         记录本应用已使用的Provider信息:<Provider发布名, ProviderRecord>

mProviderRefCountMap:  记录本应用已使用的Provider引用计数信息:<IBinder, ProviderRefCount>

mLocalProviders:      记录本地加载的Provider信息:<IBinder, ProviderRecord>

 

4)ContentProvider通知机制

Android <wbr>ContentProvider详解

 

注意:这个通知机制需要ContentProvider的实现者在实现insert/delete/query/update接口时调用ContentResolver的notifyChange(), 否则没法实现数据变化的通知。

  

参考代码:

\frameworks\base\core\java\android\app\ActivityThread.java

\frameworks\base\core\java\android\content\ContentResolver.java

\frameworks\base\core\java\android\content\ContentContent.java

\frameworks\base\core\java\android\content\ContentService.java

\frameworks\base\core\java\android\database\ContentObserver.java

\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

 

标签:10,详解,Provider,Android,ContentProvider,type
From: https://blog.51cto.com/u_16112859/6320402

相关文章

  • StackOverView又一个Android 5.0 任务管理器控件。这次这个比上次那个(MaterialRecents
    StackOverView视图布局(ViewLayout)★★★★★2015-09-2120:21147kbAndroidStudio1075次165次https://github.com/Bossyao168/StackOverView卡片,任务下载 收藏 Bossyao168 / StackOverViewacustomwidgetofandroid,liketaskmanagerofandr......
  • JAVA中的接口详解
    JAVA中的接口详解接口中成员的特点成员变量:只能是常量默认修饰符:public,static,final构造方法:没有成员方法:只能是抽象方法默认修饰符:public,abstract 接口和类的关系类和类的关系:继承关系,只能是单继承,不能多继承,但可以多层继承类和接口的关系:实现关系,可单实现,也可多实......
  • mysql联合索引详解
    所有的MySQL列类型能被索引。在相关的列上的使用索引是改进SELECT操作性能的最好方法。一、前缀索引对于CHAR和VARCHAR列,你可以索引列的前缀。这更快并且比索引整个列需要较少的磁盘空间。在CREATETABLE语句中索引列前缀的语法看起来像这样:KEYindex_name(col_name(length))下面......
  • DataFrameGroupBy.agg详解
    DataFrameGroupBy.agg(arg, *args, **kwargs)[source]Aggregateusingcallable,string,dict,orlistofstring/callablesParameters:funcFunctiontouseforaggregatingthedata.Ifafunction,musteitherworkwhenpassedaDataFrameorwhenpassedto......
  • 【Android】Uri、UriMatcher、ContentUris详解
     1.Uri通用资源标志符(UniversalResourceIdentifier,简称"URI")。Uri代表要操作的数据,Android上可用的每种资源-图像、视频片段等都可以用Uri来表示。 URI一般由三部分组成:访问资源的命名机制。 存放资源的主机名。 资源自身的名称,由路径表示。      Android的Uri由以......
  • Android数据储存之File文件储存数据
     一.存储在内部还是外部?AndroidManifest.xml中manifest标签下有一个属性android:installLocation,用于指定应用程序安装在什么地方,该属性有三个可选值:auto:程序可能被安装在外部存储器上,例如SD卡;但是默认会被安装到手机内存中。当手机内存为空时,程序将被安装到外部存储器上;当程序安......
  • 最快Android模拟器Genymotion的安装
        在这开发Android的一段时间内,一直是使用真机进行测试的,使用过的机子包括华为U8825d,红米,MX3.深知Android的最大问题就是碎片化,就是各种适配问题,甚是头疼。也是一直听说Genymotion的快速与强大,也是亲眼见过别人使用Genymotion,完全把Android自带的AVD碾压的渣都不剩。所以......
  • STM32 CAN过滤器配置详解
     STM32CAN过滤器配置详解_stm32can配置_路过的小熊~的博客-CSDN博客路过的小熊~已于 2022-07-3123:09:16 修改 1前言STM32F10X的bxCAN是基本扩展CAN(BasicExtendedCAN)的缩写,它支持CAN协议2.0A和2.0B。在CAN协议里,报文的标识符不代表节点的地址,而是和......
  • Day 41 41.1 Python中json模块的loadloads方法实战及参数详解
    Python中json模块的load/loads方法实战及参数详解【一】loads方法与load方法的异同在Python中json是一个非常常用的模块,这个主要有4个方法:json.dumpsjson.dumpjson.loadsjson.load这里主要分析讲解一下json的loads和load方法。这两个方法中都是把其他类型......
  • Day 41 41.3 URL 解码 编码详解
    【一】URL解码/编码详解当URL路径或者查询参数中,带有中文或者特殊字符的时候,就需要对URL进行编码(采用十六进制编码格式)。URL编码的原则是使用安全字符去表示那些不安全的字符。安全字符,指的是没有特殊用途或者特殊意义的字符。【二】URL基本组成URL是由一些简单的......