【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么_第1页
【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么_第2页
【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么_第3页
【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么_第4页
【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】Android7.0中ContentProvider组件的作用是什么

这篇文章将为大家详细讲解有关Android7.0中ContentProvider组件的作用是什么,文章内容质量较高,因此在下分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。作为Android的四大组件之一,ContentProvider作为进程之间静态数据传递的重要手段,其在系统级别的应用中起了重大的作用。毫无疑问,ContentProvider核心机制之一也是Binder,但是和其它3大组件又有区别。因为ContentProvider涉及数据的增删查改,当数据量比较大的时候,继续用Parcel做容器效率会比较低,因此它还使用了匿名共享内存的方式。但是有一个问题是,ContentProvider的提供者进程不再存活时,其他进程通过Provider读一个非常简单的数据时,都需要先把提供者进程启动起来(除非指定multiprocess=true),这对用户是相当不友好的。又因为其是间接通过db进行数据操作,所以效率也远不如直接操作db。因此在用户app中,不是很建议经常使用ContentProvider。不过对于系统级的app,它统一了数据操作的规范,利是远大于弊的。ContentProvider发布当进程第一次启动时候会调用handleBindApplicationif

(!data.restrictedBackupMode)

{

if

(!ArrayUtils.isEmpty(viders))

{

installContentProviders(app,

viders);

}

}当xml中有provider时,进行provider的发布final

ArrayList<IActivityManager.ContentProviderHolder>

results

=

new

ArrayList<IActivityManager.ContentProviderHolder>();

for

(ProviderInfo

cpi

:

providers)

{

IActivityManager.ContentProviderHolder

cph

=

installProvider(context,

null,

cpi,

false

/*noisy*/,

true

/*noReleaseNeeded*/,

true

/*stable*/);

if

(cph

!=

null)

{

cph.noReleaseNeeded

=

true;

results.add(cph);

}

}

try

{

ActivityManagerNative.getDefault().publishContentProviders(

getApplicationThread(),

results);

}

catch

(RemoteException

ex)

{

}@installProvider(这个方法先简单过一下,后面会继续说)final

java.lang.ClassLoader

cl

=

c.getClassLoader();

localProvider

=

(ContentProvider)cl.

loadClass().newInstance();

provider

=

localProvider.getIContentProvider();@installProviderAuthoritiesLockedfor

(String

auth

:

auths)

{

final

ProviderKey

key

=

new

ProviderKey(auth,

userId);

final

ProviderClientRecord

existing

=

mProviderMap.get(key);

if

(existing

!=

null)

{

}

else

{

mProviderMap.put(key,

pcr);

}

}这里两步把ProviderInfo通过installProvider转换成ContentProvider的Binder对象IContentProvider,并放于ContentProviderHolder中。并根据auth的不同,把发布进程的ProviderClientRecord保存在一个叫mProviderMap的成员变量中,方便第二次调用同一个ContentProvider时,无需重新到AMS中去查询。AMS@publishContentProvidersfinal

int

N

=

providers.size();

for

(int

i

=

0;

i

<

N;

i++)

{

ContentProviderHolder

src

=

providers.get(i);

...

ContentProviderRecord

dst

=

r.pubProviders.get();

if

(dst

!=

null)

{

ComponentName

comp

=

new

ComponentName(.packageName,

);

mProviderMap.putProviderByClass(comp,

dst);

String

names[]

=

.authority.split(";");

for

(int

j

=

0;

j

<

names.length;

j++)

{

mProviderMap.putProviderByName(names[j],

dst);

}

int

launchingCount

=

mLaunchingProviders.size();

int

j;

boolean

wasInLaunchingProviders

=

false;

for

(j

=

0;

j

<

launchingCount;

j++)

{

if

(mLaunchingProviders.get(j)

==

dst)

{

mLaunchingProviders.remove(j);

wasInLaunchingProviders

=

true;

j--;

launchingCount--;

}

}

if

(wasInLaunchingProviders)

{

mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,

r);

}

...

}

}可以看到,AMS会遍历所有的ContentProviderHolder,然后调用mProviderMap把信息保存起来,这块接下来说。保存好之后,先去看看之前是不是已经有launch过的,如果已经有launch过的,不再重复launch。再说说这个mProviderMap,这个和ActivityThread中的mProviderMap不太一样,这个是一个成员实例,非真正的map。看看putProviderByClass和putProviderByName。ProviderMap@putProviderByClassif

(record.singleton)

{

mSingletonByClass.put(name,

record);

}

else

{

final

int

userId

=

UserHandle.getUserId(record.appInfo.uid);

getProvidersByClass(userId).put(name,

record);

}ProviderMap@putProviderByNameif

(record.singleton)

{

mSingletonByName.put(name,

record);

}

else

{

final

int

userId

=

UserHandle.getUserId(record.appInfo.uid);

getProvidersByName(userId).put(name,

record);

}可以看到,发布的Provider实际会根据class或authority存在不同的map中。如果是单例,则分别存到相应的mSingletonmap中,否则就根据userId存到相应的map中。这样发布的过程就完成了,其他进程需要使用的时候将会在AMS按需读取。ContentReslover跨进程数据操作当我们跨进程调用数据时候,会先调用获取用户进程的ContentResolvercontext.getContentResolver().query(uri,

...);

public

ContentResolver

getContentResolver()

{

return

mContentResolver;

}而这个ContentResolver在每个进程中都存在有且唯一的实例,其在ContextImpl构造函数中就已经初始化了,其初始化的实际对象是ApplicationContentResolver。mContentResolver

=

new

ApplicationContentResolver(this,

mainThread,

user);这个ContentResolver是活在调用者进程中的,它是作为一个类似桥梁的作用。以插入为例:ContentResolver@insertIContentProvider

provider

=

acquireProvider(url);

if

(provider

==

null)

{

throw

new

IllegalArgumentException("Unknown

URL

"

+

url);

}

try

{

long

startTime

=

SystemClock.uptimeMillis();

Uri

createdRow

=

provider.insert(mPackageName,

url,

values);

...

return

createdRow;

}

catch

(RemoteException

e)

{

return

null;

}

finally

{

releaseProvider(provider);

}问题就转化成了,拿到其他进程的ContentProvider的Binder对象,有了binder对象就可以跨进程调用其方法了。ContentResolver@acquireProviderif

(!SCHEME_CONTENT.equals(uri.getScheme()))

{

return

null;

}

final

String

auth

=

uri.getAuthority();

if

(auth

!=

null)

{

return

acquireProvider(mContext,

auth);

}校验其URI,其scheme必须为content。ApplicationContentResolver@acquireProviderprotected

IContentProvider

acquireProvider(Context

context,

String

auth)

{

return

mMainThread.acquireProvider(context,

ContentProvider.getAuthorityWithoutUserId(auth),

resolveUserIdFromAuthority(auth),

true);

}这里面有个特别的函数会传递一个true的参数给ActivityThread,这意味本次连接是stable的。那stable和非stable的区别是什么呢?这么说吧:Stableprovider:若使用过程中,provider要是挂了,你的进程也必挂。Unstableprovider:若使用过程中,provider要是挂了,你的进程不会挂。但你会收到一个DeadObjectException的异常,可进行容错处理。继续往下。ActivityThread@acquireProvider

final

IContentProvider

provider

=

acquireExistingProvider(c,

auth,

userId,

stable);

if

(provider

!=

null)

{

return

provider;

}

IActivityManager.ContentProviderHolder

holder

=

null;

try

{

holder

=

ActivityManagerNative.getDefault().getContentProvider(

getApplicationThread(),

auth,

userId,

stable);

}

catch

(RemoteException

ex)

{

}

if

(holder

==

null)

{

return

null;

}

holder

=

installProvider(c,

holder,

,

true

/*noisy*/,

holder.noReleaseNeeded,

stable);

return

vider;这里面分了三步,1、寻找自身进程的缓存,有直接返回。2、缓存没有的话,寻找AMS中的Provider。3、InstallProvider,又到了这个方法。怎么个install法?还是一会儿再说。@acquireExistingProvider(寻找自身缓存)synchronized

(mProviderMap)

{

final

ProviderKey

key

=

new

ProviderKey(auth,

userId);

final

ProviderClientRecord

pr

=

mProviderMap.get(key);

if

(pr

==

null)

{

return

null;

}

IContentProvider

provider

=

pr.mProvider;

IBinder

jBinder

=

provider.asBinder();

...

ProviderRefCount

prc

=

mProviderRefCountMap.get(jBinder);

if

(prc

!=

null)

{

incProviderRefLocked(prc,

stable);

}

return

provider;这一步就是读取我们发布时提到的mProviderMap中的缓存。当provider记录存在,且进程存活的情况下,则在provider引用计数不为空时则继续增加引用计数。缓存不存在,则去AMS中找AMS@getContentProviderImplContentProviderRecord

cpr;

cpr

=

mProviderMap.getProviderByName(name,

userId);

if

(providerRunning){

if

(r

!=

null

&&

cpr.canRunHere(r))

{

ContentProviderHolder

holder

=

cpr.newHolder(null);

vider

=

null;

return

holder;

}

}

public

boolean

canRunHere(ProcessRecord

app)

{

return

(info.multiprocess

||

cessName.equals(cessName))

&&

uid

==

.uid;

}Provider是提供保护数据的接入访问的。一般情况下,不同进程的访问只能通过IPC来进行,但那是有些情况是可以允许访问者在自己的进程中创建本地Provider来进行访问的。这种情况是在UID必须相同的前提下,要么同一进程,要么provider设定了multiprocess为true。if

(!providerRunning)

{

cpi

=

AppGlobals.getPackageManager().resolveContentProvider(name,

STOCK_PM_FLAGS

|

PackageManager.GET_URI_PERMISSION_PATTERNS,

userId);

...

ComponentName

comp

=

new

ComponentName(cpi.packageName,

);

cpr

=

mProviderMap.getProviderByClass(comp,

userId);

if

(r

!=

null

&&

cpr.canRunHere(r))

{

return

cpr.newHolder(null);

}

ProcessRecord

proc

=

getProcessRecordLocked(

cessName,

cpr.appInfo.uid,

false);

if

(proc

!=

null

&&

proc.thread

!=

null)

{

if

(!proc.pubProviders.containsKey())

{

proc.pubProviders.put(,

cpr);

proc.thread.scheduleInstallProvider(cpi);

}

}

else

{

proc

=

startProcessLocked(cessName,

cpr.appInfo,

false,

0,

"content

provider",

new

ComponentName(cpi.applicationInfo.packageName,

),

false,

false,

false);

}

}

}

mProviderMap.putProviderByName(name,

cpr);

}这块步骤比较多,挑重点就是,先从AMS的ProviderMap对象中获取AMS缓存。获得后如果Provider没有launch,则AMS通知其进程install其provider。如果进程不存在,则新孵化一个进程。@InstallProvider回到第三步中的installProviderprivate

IActivityManager.ContentProviderHolder

installProvider(Context

context,

IActivityManager.ContentProviderHolder

holder,

ProviderInfo

info,

boolean

noisy,

boolean

noReleaseNeeded,

boolean

stable)可以看到,这个方法里面有6个参数,其中包含ContentProviderHolder、ProviderInfo、noReleaseNeeded,这几个很重要的参数。ContentProviderHolder:当参数为空的时候,说明缓存为空,也就意味着是进程启动的时候调用发布provider。当缓存不为空的时候,还得做一些处理。ProviderInfo:包含Provider的一些信息,不能为空。noReleaseNeeded:为true的时候Provider对于自身进程来说或系统的Provider,是永久install的,也就是不会被destory的。ContentProvider

localProvider

=

null;

IContentProvider

provider;

if

(holder

==

null

||

vider

==

null)

{

try

{

final

java.lang.ClassLoader

cl

=

c.getClassLoader();

localProvider

=

(ContentProvider)cl.

loadClass().newInstance();

provider

=

localProvider.getIContentProvider();

if

(provider

==

null)

{

return

null;

}

localProvider.attachInfo(c,

info);

}

catch

(java.lang.Exception

e)

{

}

}

else

{

provider

=

vider;

}这部分在发布的时候已经说了,缓存holder为null的时候,new一个实例。IActivityManager.ContentProviderHolder

retHolder;

synchronized

(mProviderMap)

{

IBinder

jBinder

=

provider.asBinder();

if

(localProvider

!=

null)

{

ComponentName

cname

=

new

ComponentName(info.packageName,

);

ProviderClientRecord

pr

=

mLocalProvidersByName.get(cname);

if

(pr

!=

null)

{

provider

=

pr.mProvider;

}

else

{

holder

=

new

IActivityManager.ContentProviderHolder(info);

vider

=

provider;

holder.noReleaseNeeded

=

true;

pr

=

installProviderAuthoritiesLocked(provider,

localProvider,

holder);

mLocalProviders.put(jBinder,

pr);

mLocalProvidersByName.put(cname,

pr);

}

retHolder

=

pr.mHolder;

}

else

{

...

}如果localProvider不等于null,则意味着是new一个实例的情况,这时候还是先去获取缓存,没有的话再真正地new一个ContentProviderHolder实例,并把通过installProviderAuthoritiesLocked方法把相关信息存入mProviderMap中,这个就是对应发布Provider提的那个方法。IActivityManager.ContentProviderHolder

retHolder;

synchronized

(mProviderMap)

{

...

}

else

{

ProviderRefCount

prc

=

mProviderRefCountMap.get(jBinder);

if

(prc

!=

null)

{

if

(!n

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论