你好 我的苹果5s电池饿死激活方法了怎么在家自己激活啊

查看:19623|回复:17
资深技术经理
ContentProvider是android组件之一,可以提供数据的跨应用程序访问,提供数据的跨进程无缝隙访问,所以是非常重要的东东。使用方法一般是复制内容到剪贴板代码:getContentResolver().query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);那么下面来提几个问题:
1. 在应用程序A里面怎么跨进程拿到ContentProvider的对象呢?
2. ContentProvider实例对象是保存在哪里呢?
3. ContentProvider的方法实现要注意线程安全吗?
如果你能很清晰的回答这几个问题,那么下面的你就不需要继续看了,如果还有疑问,咱们一起往下面学习吧~
(二) 怎么跨进程拿到ContentProvider的对象
1. 我们来看ContentResolver.query方法是怎么实现的
a. 首先它会去找ContentProvider对象,是这样写的复制内容到剪贴板代码:IContentProvider unstableProvider = acquireUnstableProvider(uri);b. 然后acquireUnstableProvider(uri)方法是这样的:复制内容到剪贴板代码:public final IContentProvider acquireUnstableProvider(Uri uri) {
& && &&&if (!SCHEME_CONTENT.equals(uri.getScheme())) {
& && && && &
& && &&&String auth = uri.getAuthority();//取得ContentProvider名字,拿这个名字去寻找对应的ContentProvider
& && &&&if (auth != null) {
& && && && &return acquireUnstableProvider(mContext, uri.getAuthority());
& & }在这段代码里面,关键地方在这里 String auth = uri.getAuthority();这里取得的auth就是我们在AndroidManifes.xml文件中配置的ContentProvider的android:authorities的值
如:复制内容到剪贴板代码:&provider android:name=&.TestProvider&
& && && && && & android:authorities=&com.android.test&&&/provider&所以,这个android:authorities属性配置的就是该ContentProvider的名字,是它在Android系统中的名字,我们是通过这个名字去找对应的ContentProvider对象的。
c. ok..既然现在我们拿到ContentProvider的名字了,我们就来看看acquireUnstableProvider方法怎么通过名字来找到ContentProvider对象的。
这个acquireUnstableProvider方法会调用到ActivityThread的acquireProvider方法,这个方法的实现是:复制内容到剪贴板代码:public final IContentProvider acquireProvider(Context c, String name, boolean stable) {
& && &&&IContentProvider provider = acquireExistingProvider(c, name, stable);
& && &&&if (provider != null) {
& && && && &
& && &&&// There is a possible race here.&&Another thread may try to acquire
& && &&&// the same provider at the same time.&&When this happens, we want to ensure
& && &&&// that the first one wins.
& && &&&// Note that we cannot hold the lock while acquiring and installing the
& && &&&// provider since it might take a long time to run and it could also potentially
& && &&&// be re-entrant in the case where the provider is in the same process.
& && &&&IActivityManager.ContentProviderHolder holder =
& && &&&try {
& && && && &holder = ActivityManagerNative.getDefault().getContentProvider(
& && && && && && &&&getApplicationThread(), name, stable);
& && &&&} catch (RemoteException ex) {
& && &&&if (holder == null) {
& && && && &Slog.e(TAG, &Failed to find provider info for & + name);
& && && && &
& && &&&// Install provider will increment the reference count for us, and break
& && &&&// any ties in the race.
& && &&&holder = installProvider(c, holder, ,
& && && && && & true /*noisy*/, holder.noReleaseNeeded, stable);
& && &&&return holder.
& & }这里就是查找ContentProvider实现的精髓所在了。。
首先,它去找acquireExistingProvider方法,这个方法其实就是根据我们传过来的名称在一个map里面找,如:
ProviderClientRecord pr = mProviderMap.get(name);
由于我们的ActivityThread和我们的应用程序还在一个进程里面,所以这个步骤我们可以理解为:在本地缓存中寻找ContentProvider对象
ok...在本地找了之后,如果找到了,就直接返回。
if (provider != null) {
& && && && &
如果没有找到,就继续往下面走:
holder = ActivityManagerNative.getDefault().getContentProvider(
& && && && && && &&&getApplicationThread(), name, stable);
这个方法就是调用到ActivityManagerService的getContentProvider方法去寻找ContentProvider.这里是一个跨进程调用,因为ActivityThread和ActivityManagerService不在一个进程里面。
至于ActivityThread和ActivityManagerService的关系,可以参考我以前的这篇帖子:
而ActivityManagerService会把所有的ContentProvider都实例化出来,并且缓存在一个map里面,所以我们就可以通过复制内容到剪贴板代码:holder = ActivityManagerNative.getDefault().getContentProvider(
& && && && && && &&&getApplicationThread(), name, stable);从ActivityManagerService远程得到一个ContentProvider对象。那么这一步,我们可以理解为:从远程服务中寻找ContentProvider对象
ok..从远程ActivityManagerService得到ContentProvider对象之后,我们继续往下面走。复制内容到剪贴板代码:holder = installProvider(c, holder, ,
& && && && && & true /*noisy*/, holder.noReleaseNeeded, stable);
& && &&&return holder.首先,会调用installProvider方法,这个方法其实就是往本地的ContentProvider map缓存中添加一条缓存记录。
ok...那么这整个过程,我们就可以理解为这样:
i.&&第一步,它从ActivityThread里面本地缓存寻找ContentProvider对象,所以找到了,就一切ok..
ii. 第二步,如果第一步没有找到,那么就去ActivityManagerService远程服务中寻找ContentProvider对象。
iii.第三步,从远程服务中找到ContentProvider对象之后,就把这个对象缓存在本地,那么下次找的话,直接就可以从本地缓存中查找了。
那么,它为什么要有这个机制呢?个人猜测:因为跨进程调用是需要时间和资源消耗的,所以,它才有了本地缓存这么个东东。
(三) ContentProvider实例对象是保存在哪里
那么如果大家看完了上面一篇长篇大论,这个问题就很好回答了。
它储存在两个位置:
1. ActivityThread的本地map缓存中
2. ActivityManagerService的远程服务map缓存中
(四) ContentProvider的方法实现要注意线程安全吗
从上面一段描述来看,我们可以发现一个问题,ContentProvider在某种程度上是单例的,比如我们第一次从本地map缓存里面得到ContentProvider对象,第二次我们在同一个应用程序请求的时候,拿到的肯定是同一个缓存对象。
所以,ContentProvider只能配置进程之间是否是单例,同一个进程里面是不能配置是否是单例的,因为它在同一个进程里面肯定是单例。
配置进程之间是否是单例:复制内容到剪贴板代码:android:multiprocess=&true&所以我们的ContentProvider的代码,比如查询,更新,删除等等,必须注意线程安全的问题。
那么单例下,我们怎么注意线程安全问题呢?
1. ContentProvider尽量少用成员变量,因为我们用的是单例,所以成员变量是共享的。
2. 所以真的用到了共享资源,建议用synchronized或者TheadLocal来解决。至于synchronized和TheadLocal的区别,这篇文章就不讨论了,下次有机会再写吧。。
一点点小小分析,仅供参考~~
本帖最后由 rongwei84n 于
10:23 编辑
资深技术经理
很长,有木有~~:lol1
中级工程师
写的很好,很仔细!
资深技术经理
引用:原帖由 四海轩 于
11:23 发表
写的很好,很仔细! 多谢捧场~, 大家有钱的捧个钱场,没钱的捧个人场哈~;P1
助理工程师
:lol1 感谢分享....最近各种加班....4月1号大上载....我可爱的晚上没了 就连我亲生一般的周六 日 也随之没了
来,鼓励一下~~
资深技术经理
引用:原帖由 林的理想 于
15:30 发表
:lol1 感谢分享....最近各种加班....4月1号大上载....我可爱的晚上没了 就连我亲生一般的周六 日 也随之没了 这这, 也太辛苦了吧。。:(1
感谢楼主分享。:lol1
资深技术经理
引用:原帖由
22:49 发表
感谢楼主分享。:lol1 感谢支持~~ :lol1
虽然,,,虽然目前还没有学到,但是楼主一直很牛。赞一个。
中级工程师
contentprovider 是通过uri来找到的,听说保存的东东还是通过数据库保存的,楼主有空的时候,也讲讲哦!我基础不够,喜欢楼主的深层剖析!
助理工程师
非常不错,感谢楼主分享!
资深技术经理
引用:原帖由 mohen266 于
17:21 发表
虽然,,,虽然目前还没有学到,但是楼主一直很牛。赞一个。 谢谢支持,其实只要能和大家一起讨论,学习就好了。。
资深技术经理
引用:原帖由 四海轩 于
17:38 发表
contentprovider 是通过uri来找到的,听说保存的东东还是通过数据库保存的,楼主有空的时候,也讲讲哦!我基础不够,喜欢楼主的深层剖析! 嗯嗯, 等来到深圳之后,我再和大家一起来51CTO~~
资深技术经理
引用:原帖由 xblqmxz 于
18:00 发表
非常不错,感谢楼主分享! 多谢捧场~
感觉受益匪浅~~
资深技术经理
引用:原帖由 caonidayeheixiu 于
10:07 发表
感觉受益匪浅~~ 谢谢支持~ :)1
其实,我想问问楼主,一般我们操作contentResolver的四个方法都会放在线程里面执行,那么这四个方法最终是会调用contentProvider的对应的方法。那么是不是contentProvider相应的方法也执行在工作线程中?如果不是的话,执行长时间的任务就会阻塞主线程了吧,如果是的话,系统是如何保证它执行在非主线程中呢?
资深技术经理
引用:原帖由 tianyasifan 于
18:13 发表
其实,我想问问楼主,一般我们操作contentResolver的四个方法都会放在线程里面执行,那么这四个方法最终是会调用contentProvider的对应的方法。那么是不是contentProvider相应的方法也执行在工作线程中?如果不是的话,执行长 ... ContentProvider响应应用程序的调用时,会开启子线程来执行工作。
再深入的讲的话,就是binder线程来执行工作。
因为ContentProvider的原理有一部分使用的是binder机制,binder驱动在回调ContentProvider进程时,会去从binder线程池(一般15个binder线程)中找到一个binder线程,来响应客户端应用程序的调用。
这个你可以去看看binder机制。Android学习(102)
ContentProvider是Android四大组件之一,承担着跨进程数据访问的重要职责。本文就从一次ContentProvider访问入手,分析下它是怎么完成跨进程数据访问的。
  既然是跨进程,那就必须有一个客户端进程和一个ContentProvider进程,我们先从客户端进程分析,看它如何访问ContentProvider进程。以Query操作为例,一般情况下,当我们需要访问ContentProvider的时候一般都会执行这么一句:
getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
  ContentResolver是什么?Google的解释是“This class provides applications access to the content model”。实际上我们正是通过ContentResolver来获取一个IContentProvider对象,通过IContentProvider对象我们尽可以进行IPC通讯了。getContentResolver()方法定义Context类中,实际上Context是一个抽象类,在客户端应用程序中getContext()实际上返回的是一个ContextImp对象,getContentResolver()方法就定义在ContextImp.java中,并且最终返回ContextImp的内部类ApplicationContentResolver,从名字上看这是一个Application级别的对象。
  ApplicationContentResolver我们稍后再说,先看下query方法都干了什么:
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
IContentProvider stableProvider = null;
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
qCursor = unstableProvider.query(uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died...
but we only hold an unstable
// reference though, so we might recover!!!
Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
qCursor = stableProvider.query(uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
if (qCursor == null) {
return null;
// force query execution
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startT
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
if (stableProvider != null) {
releaseProvider(stableProvider);
  上面的代码有四个关键步骤:
  1.&acquireUnstableProvider
  2.&unstableProvider.query(......)
  3.&qCursor.getCount();
  4. return new CursorWrapperInner(......)
  接下来我们一步一步分析这四个关键步骤。
  第一步:acquireUnstableProvider
  乍看上去感觉怪怪的,好端端的为什么加上了一个Unstable的标签?难道还有stable的不成?事实确实如此,我们知道此时的ContentResolver实际上是一个ApplicationContentResovler对象,来看下ApplicationContentResovler
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainT
private final UserHandle mU
public ApplicationContentResolver(
Context context, ActivityThread mainThread, UserHandle user) {
super(context);
mMainThread = Preconditions.checkNotNull(mainThread);
mUser = Preconditions.checkNotNull(user);
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
protected IContentProvider acquireExistingProvider(Context context, String auth) {
return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true);
public boolean releaseProvider(IContentProvider provider) {
return mMainThread.releaseProvider(provider, true);
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
public boolean releaseUnstableProvider(IContentProvider icp) {
return mMainThread.releaseProvider(icp, false);
public void unstableProviderDied(IContentProvider icp) {
mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
  实际上,是否是stable的,都将调用ActivityThread的acquireProvider方法,区别就是最后的一个参数boolean stable。这个机制是API 16引入的,文章的最后会对此进行说明。现在我们只要知道它最终走到了ActivityThread的acquireProvider就可以了。在ActivityThread的acquireProvider方法中,我们首先会去acquireExistingProvider,从字面上就可以看出这是从一个类缓存的地方读取已经保存的ContentProvider对象,如果不存在,就会调用ActivityManagerNative.getDefault().getContentProvider(getApplicationThread(),
auth, userId, stable);从这儿开始,ActivityManagerService就要登场了,上面的代码最终会通过binder通信调用ActivityManagerService的getContentProviderImpl,这块的逻辑比较复杂,涉及到了Android组件启动的过程,我们只需知道客户端调用会阻塞在ActivityManagerNative.getDefault().getContentProvider,ActivityManagerService启动目标ContentProvider进程后(如果ContentProvider进程已经存在则不必重启),返回一个目标ContentProvider的实例。在这儿需要说明的是,ContentProvider可以再Manifest中配置一个叫做android:multiprocess的属性,默认值是false,表示ContentProvider是单例的,无论哪个客户端应用的访问都将是一个ContentProvider对象(当然,必须是同一个ContentProvider,即Uri或者Authority
name是一个),如果设为true,系统会为每一个访问该ContentProvider的进程创建一个实例。因为android:multiprocess的默认值是false,所以我们在写自己的ContentProvider的时候还是要注意并发的情况。
  扯得有点远了,回到我们之前步骤,我们已经得到了ContentProvider的实例,这个时候第一步就完成了,接下来看第二步。
  第二步:unstableProvider.query(......)
  unstableProvider实际上是IContentProvider实例,IContentProvider是进行IPC通讯的接口,这个query实际上调用的是目标ContentProvider中的query方法,当然,在真正调用目标ContentProvider的query方法之前,还需要经过enforceReadPermission方法,这一步主要是看下该ContentProvier有没有export,读写权限等等(enforceReadPermission方法只判断读权限)。随后执行query方法,并且返回一个cursor对象。
  以上就是第二步的大致逻辑,不过不要以为这么简单就结束了。IContentProvider的query可是跨进程的,我们知道ContentProvider的query方法可是五花八门,有访问数据库返回SQLiteCursor的,有返回MatrixCursor的等等,那么IContentProvider返回的那个cursor到底是什么呢?我们来看下IContentProvider的这个IPC通信到底是怎么回事
  IPC通信需要两端,对于我们的例子,这两段分别是ContentProviderProxy和ContentProviderNative,首先会执行ContentProviderProxy的query方法,然后通过binder通信执行ContentProviderNative的onTransact方法。ContentProviderProxy的query方法有一下五个主要步骤:
  1.&new一个BulkCursorToCursorAdaptor对象——adaptor
  2. 填充data用于binder通信
  3. 调用mRemote.transact,这是一个阻塞的过程,直到ContentProviderNative的onTransact方法返回
  4. 读取reply数据,new一个BulkCursorDescriptor并以此初始化adaptor
  5. return&adaptor
  ContentProviderNative的onTransact会调用ContentProvider的query方法,并根据query返回的cursor初始化一个CursorToBulkCursorAdaptor对象,最终将BulkCursorDescriptor对象写入reply中。
  至此我们知道了,不管我们的ContentProvider query方法返回的到底是什么样的cursor,最终在客户端进程都将会被封装在一个BulkCursorToCursorAdaptor对象中,那么这个BulkCursorToCursorAdaptor对象是不是就是我们在客户端调用query返回的最终类型呢?别急,往下看。
  第三步:qCursor.getCount();
  这一步看似鸡肋,实际上涉及到了SQLiteCursor的一个设计要点,那就是SQLiteCursor的内存共享。getCount会调用SQLiteCursor的fillWindow,在以后的文章中我会在讲到SQLiteCursor,在此我们只要知道它是强制执行数据库query就可以了。
  第四步:return new CursorWrapperInner(......)
  哈,看到了吧,我们在客户端调用query最终返回的是一个CursorWrapperInner类型,它是ContentResolver的一个内部类。实际上我们常用的getCount,onMove等一些列方法都是通过BulkCursorToCursorAdaptor和CursorToBulkCursorAdaptor的交互实现的。
  到此,ContentProvider的访问流程就结束了,下面说一下开头买的坑:unstable和stable的ContentProvider。
  在4.1之前,我们都可能会遇到过这样的场景,我们的应用程序访问了ContentProvider,但是这个ContentProvider意外挂了,这个时候我们的应用程序也将被连带杀死!这是Android处于对数据安全的考虑而做的决定,不过貌似Google也感觉这样的方式不太友好,所以在4.1以后提出了stable和unstable的概念。对于ContentResolver的query方法,我们将默认使用unstable的ContentProvider。看看下面的代码
       Cursor qC
qCursor = unstableProvider.query(uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died...
but we only hold an unstable
// reference though, so we might recover!!!
Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
qCursor = stableProvider.query(uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
  上面是ContentResolver query中的一部分,可以看出unstable ContentProvider在query过程中如果发生了DeadObjectExeption则会被捕获,进而重新获取一个stable的ContentProvider。其实深入分析stable和unstable的ContentProvider还会有很多内容,以后有时间再说。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:375200次
积分:3532
积分:3532
排名:第8436名
原创:15篇
转载:179篇
评论:64条
(1)(2)(2)(1)(2)(1)(1)(2)(2)(2)(7)(17)(6)(4)(11)(10)(12)(1)(1)(1)(3)(2)(4)(26)(6)(5)(34)(3)(2)(7)(10)(6)跨应用数据提供的解决:ContentProvider和ContentResolver - 博客频道 - CSDN.NET
shareye1992的博客
分类:android存储Android工具android基础
看到这里的时候咱们假设满足一下一个或几个前提:
⑴你看过别人的博客,但是对实际应用还是有些迷惑:
⑵或者你对大概流程似乎有一点理解,但还是不明了;
⑶你干脆就是懒,只想用一下,懒得去理解
1~3的内容是比较死的套路,但是内容灵活
1.先从Manifest开始说,如下图:
新建ContentProvider的类是要在manifest里面注册的,当然,因为它也是四大组件嘛,要注册在&application&的里面。对于他的属性,那么和activity是一样的,不用多说,authorities属性很关键,这个属性是用来唯一标示当前Provider的标志,一般使用包名加类名,当然随便写也是可以的,但是...
2.Provider类的声明部分:
static{}里面是静态代码块,会优先执行。在下面代码使用uriMatcher.match(uri)&&&&时返回的int值(就是第三个参数)就是这里注册的,很关键。当然了,如果你的是包括好几种数据方式,那就有几种定义几种,然后一一对应都注册上。&&
&AUTHORITY和manifest中的authorities是一样,必须一样。强制要求,不然出问题。
3.Provider的返回数据部分
当有多种查询(增删改也一样)需求的时候,就需要根据&uriMatcher.match(uri)&做出对应处理了,这个就不想洗说了
4.关于getType()方法:
我相信很多人都迷惑过,也搞不清楚,下面链接讲的还是比较详细的,推荐看一下
这里复制一下他的结论:覆盖ContentProvider的getType方法对于用new&Intent(String&action,&Uri&uri)方法启动activity是很重要的,如果它返回的MIME&type和activity在&intent&filter&中定义的data的MIME&type不一致,将造成activity无法启动。
再简单点就是:你不用uri隐式启动(好像是这个名字)的时候,你完全可以不管他的。
5.到了你这里,当你运行程序以后,用别的app调用时你会感慨:
氧化钙!为什么没有数据!!
其实前面留了一个坑,如果想跨应用的话(废话!),就在manifest里面加上一句,如下图:
6.ContentResolver:
比Provider理解上简单多了,就是简单的数据库操作,只是你不使用数据库表名而是使用Uri,而且只能对Provider提供的内容进行处理(换个表达:Urii就是严格定义并限制了你被允许的操作,只能少不能多)。
就这些吧,老夫贴图,就是不直接粘代码,哈哈哈!
shareye1992
排名:千里之外
(25)(14)(2)(9)(17)(1)(0)(6)(2)(4)(1)(1)(0)

我要回帖

更多关于 苹果5s电池饿死 的文章

 

随机推荐