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

ContentProvider组件(跨进程)及源码-Android

2016-03-20 01:48 459 查看
问题:

1. 在应用程序A里面怎么跨进程拿到ContentProvider的对象呢?

2. ContentProvider实例对象是保存在哪里呢?

3. ContentProvider的方法实现要注意线程安全吗?

1.适用场景

1) ContentProvider为存储和读取数据提供了统一的接口

2) 使用ContentProvider,应用程序可以实现数据共享

3) android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)

ContentProvider实例化:

ActivityManagerService会把所有的ContentProvider都实例化出来,并且缓存在一个map里面,所以我们就可以通过holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), name, stable);

首先,会调用installProvider方法,这个方法其实就是往本地的ContentProvider map缓存中添加一条缓存记录。 那么这整个过程,我们就可以理解为这样:

i. 第一步,它从ActivityThread里面本地缓存寻找ContentProvider对象,所以找到了,就一切ok..

ii. 第二步,如果第一步没有找到,那么就去ActivityManagerService远程服务中寻找ContentProvider对象。

iii.第三步,从远程服务中找到ContentProvider对象之后,就把这个对象缓存在本地,那么下次找的话,直接就可以从本地缓存中查找了。

ContentProvider实例对象储存在两个位置:

1. ActivityThread的本地map缓存中

2. ActivityManagerService的远程服务map缓存中

所以,ContentProvider只能配置进程之间是否是单例,同一个进程里面是不能配置是否是单例的,因为它在同一个进程里面肯定是单例。

配置进程之间是否是单例:android:multiprocess="true"。 所以我们的ContentProvider的代码,比如查询,更新,删除等等,必须注意线程安全的问题。

》那么单例下,我们怎么注意线程安全问题呢?

1. ContentProvider尽量少用成员变量,因为我们用的是单例,所以成员变量是共享的。

2. 所以真的用到了共享资源,建议用synchronized或者TheadLocal来解决。至于synchronized和TheadLocal的区别

<provider android:name="SettingsProvider"

android:authorities="settings"

android:process="system" android:multiprocess="false"

android:writePermission="android.permission.WRITE_SETTINGS"

android:initOrder="100" />

》从SystemServer.java中的

Log.i(TAG, "Starting System Content Providers.");

ActivityManagerService.installSystemProviders();

到ActivityManagerService.java中的

public static final void installSystemProviders() {

ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);

List providers = mSelf.generateApplicationProvidersLocked(app);

mSystemThread.installSystemProviders(providers);

}

再到ActivityThread.java:

public final void installSystemProviders(List providers) {

if (providers != null) {

installContentProviders(mInitialApplication,

(List<ProviderInfo>)providers);

}

}

private final void installContentProviders(

Context context, List<ProviderInfo> providers) {

final ArrayList<IActivityManager.ContentProviderHolder> results =

new ArrayList<IActivityManager.ContentProviderHolder>();

Iterator<ProviderInfo> i = providers.iterator();

while (i.hasNext()) {

ProviderInfo cpi = i.next();

StringBuilder buf = new StringBuilder(128);

buf.append("Publishing provider ");

buf.append(cpi.authority);

buf.append(": ");

buf.append(cpi.name);

Log.i(TAG, buf.toString());

IContentProvider cp = installProvider(context, null, cpi, false);

if (cp != null) {

IActivityManager.ContentProviderHolder cph =

new IActivityManager.ContentProviderHolder(cpi);

cph.provider = cp;

results.add(cph);

// Don't ever unload this provider from the process.

synchronized(mProviderMap) {

mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));

}

}

}

1.通过获得这些ContentProvider可以查询它们包含的数据,当然前提是已获得适当的读取权限。ContentProvider主要方法:

public boolean onCreate() 在创建ContentProvider时调用

public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor

public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中

public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据

public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据

public String getType(Uri) 用于返回指定的Uri中的数据的MIME类型

*如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头。

例如:要得到所有person记录的Uri为content://contacts/person,那么返回的MIME类型字符串为"vnd.android.cursor.dir/person"。

*如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。

例如:要得到id为10的person记录的Uri为content://contacts/person/10,那么返回的MIME类型字符串应为"vnd.android.cursor.item/person"。

2.要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。

public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。

public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。

3.Uri

Uri指定了将要操作的ContentProvider,其实可以把一个Uri看作是一个网址,我们把Uri分为三部分。

第一部分是"content://"。可以看作是网址中的"http://"。

第二部分是主机名或authority,用于唯一标识这个ContentProvider,外部应用需要根据这个标识来找到它。可以看作是网址中的主机名,比如"blog.csdn.net"。

第三部分是路径名,用来表示将要操作的数据。可以看作网址中细分的内容路径。

》要创建我们自己的Content Provider的话,我们需要遵循以下几步:

a. 创建一个继承了ContentProvider父类的类

b. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如:

public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);

c. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。

d. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。

e. 如果你要存储字节型数据,比如位图文件等,数据列其实是一个表示实际保存文件的URI字符串,通过它来读取对应的文件数据。处理这种数据类型的Content Provider需要 实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用 ContentResolver.openOutputStream()方法来处理该URI指向的文件资源;如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文
件。

f. 声明public static String型的变量,用于指定要从游标处返回的数据列。

g. 查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。

h. 在AndroidMenifest.xml中使用<provider>标签来设置Content Provider。

i. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:

  vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型)

  比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。

  vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型)

  比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。

》ContentProvider的使用示例:

public class MyContentProvider extends ContentProvider {

private SQLiteDatabase sqlDB;

private DatabaseHelper dbHelper;

private static final String DATABASE_NAME = “Users.db”;

private static final int DATABASE_VERSION= 1;

private static final String TABLE_NAME= “User”;

private static final String TAG = “MyContentProvider”;

private static class DatabaseHelper extends SQLiteOpenHelper {

DatabaseHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

@Override

public void onCreate(SQLiteDatabase db) {

//创建用于存储数据的表

db.execSQL(”Create table ” + TABLE_NAME + “( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);”);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

db.execSQL(”DROP TABLE IF EXISTS ” + TABLE_NAME);

onCreate(db);

}

}

@Override

public int delete(Uri uri, String s, String[] as) {

return 0;

}

@Override

public String getType(Uri uri) {

return null;

}

@Override

public Uri insert(Uri uri, ContentValues contentvalues) {

sqlDB = dbHelper.getWritableDatabase();

long rowId = sqlDB.insert(TABLE_NAME, “”, contentvalues);

if (rowId > 0) {

Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();

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

return rowUri;

}

throw new SQLException(”Failed to insert row into ” + uri);

}

@Override

public boolean onCreate() {

dbHelper = new DatabaseHelper(getContext());

return (dbHelper == null) ? false : true;

}

@Override

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

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

SQLiteDatabase db = dbHelper.getReadableDatabase();

qb.setTables(TABLE_NAME);

Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);

c.setNotificationUri(getContext().getContentResolver(), uri);

return c;

}

@Override

public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {

return 0;

}

}

源码分析:

ContentProvider主要做了以下几件事:

(1)根据传递过来的name创建了ProviderInfo对象和ApplicationInfo对象,然后根据它们两个对象创建了ContentProviderRecord对象。

(2)创建了ProcessRecord对象,并创建ArticlesProvider子线程。

(3)循环等待cpr.provider的值不为null。

第一步:~/Android/frameworks/base/core/java/android/app

----ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager{

......

public ContentProviderHolder getContentProvider(IApplicationThread caller,

String name) throws RemoteException{

Parcel data = Parcel.obtain();

Parcel reply = Parcel.obtain();

data.writeInterfaceToken(IActivityManager.descriptor);

data.writeStrongBinder(caller != null ? caller.asBinder() : null);

data.writeString(name);

mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);

reply.readException();

int res = reply.readInt();

ContentProviderHolder cph = null;

if (res != 0) {

cph = ContentProviderHolder.CREATOR.createFromParcel(reply);

}

data.recycle();

reply.recycle();

return cph;

}

......

}

其中name为shy.luo.providers.articles。如图:第二步,省略binder_transaction传输过程,因为上面已经分析过了。

第三步: ~/Android/frameworks/base/core/java/android/app

----ActivityManagerNative.java

public abstract class ActivityManagerNative extends Binder implements IActivityManager

{

......

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)

throws RemoteException {

switch (code) {

case GET_CONTENT_PROVIDER_TRANSACTION: {

data.enforceInterface(IActivityManager.descriptor);

IBinder b = data.readStrongBinder();

IApplicationThread app = ApplicationThreadNative.asInterface(b);

String name = data.readString();

ContentProviderHolder cph = getContentProvider(app, name);

reply.writeNoException();

if (cph != null) {

reply.writeInt(1);

cph.writeToParcel(reply, 0);

} else {

reply.writeInt(0);

}

return true;

}

.......

}

其中name为shy.luo.providers.articles。

第四步: ~/Android/frameworks/base/services/java/com/android/server/am

----ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative

implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

......

public final ContentProviderHolder getContentProvider(

IApplicationThread caller, String name) {

......

return getContentProviderImpl(caller, name);

}

......

}

它调用getContentProviderImpl函数来进一步执行操作。

public final class ActivityManagerService extends ActivityManagerNative

implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

......

private final ContentProviderHolder getContentProviderImpl(

IApplicationThread caller, String name) {

ContentProviderRecord cpr;

ProviderInfo cpi = null;

synchronized(this) {

ProcessRecord r = null;

if (caller != null) {

r = getRecordForAppLocked(caller);

......

}

// First check if this content provider has been published...

cpr = mProvidersByName.get(name);

if (cpr != null) {

......

} else {

try {

cpi = AppGlobals.getPackageManager().

resolveContentProvider(name,

STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);

} catch (RemoteException ex) {

}

......

}

cpr = mProvidersByClass.get(cpi.name);

final boolean firstClass = cpr == null;

if (firstClass) {

try {

ApplicationInfo ai =

AppGlobals.getPackageManager().

getApplicationInfo(

cpi.applicationInfo.packageName,

STOCK_PM_FLAGS);

......

cpr = new ContentProviderRecord(cpi, ai);

} catch (RemoteException ex) {

// pm is in same process, this will never happen.

}

}

if (r != null && cpr.canRunHere(r)) {

// If this is a multiprocess provider, then just return its

// info and allow the caller to instantiate it. Only do

// this if the provider is the same user as the caller's

// process, or can run as root (so can be in any process).

return cpr;

}

......

// This is single process, and our app is now connecting to it.

// See if we are already in the process of launching this

// provider.

final int N = mLaunchingProviders.size();

int i;

for (i=0; i<n; i++)="" {="" if="" (mlaunchingproviders.get(i)="=" cpr)="" break;="" }="" the="" provider="" is="" not="" already="" being="" launched,="" then="" get="" it="" started.="" (i="">= N) {

final long origId = Binder.clearCallingIdentity();

ProcessRecord proc = startProcessLocked(cpi.processName,

cpr.appInfo, false, 0, "content provider",

new ComponentName(cpi.applicationInfo.packageName,

cpi.name), false);

......

mLaunchingProviders.add(cpr);

......

}

// Make sure the provider is published (the same provider class

// may be published under multiple names).

if (firstClass) {

mProvidersByClass.put(cpi.name, cpr);

}

cpr.launchingApp = proc;

mProvidersByName.put(name, cpr);

......

}

// Wait for the provider to be published...

synchronized (cpr) {

while (cpr.provider == null) {

......

try {

cpr.wait();

} catch (InterruptedException ex) {

}

}

}

return cpr;

}

一、前言

ContentProvider作为Android四大组件之一,承担着数据存储的作用,本文用一个最典型的删除(delete)操作,按照Android源码,从应用层的getContentResolver()入手,一步步的分析到ContentProvider内部,最终到达SQLite的操作。

getContentResolver().delete();这个简单的操作其实包含了两个步骤:

1、通过getContentResolver()得到需要的ContentProvider对象;

2、通过delete()操作,将ContentProvider中的数据删除;

二、getContentResolver

看标题,我们是要得到一个ContentResolver的对象,这就产生了两个疑问:

1、ContentResolver对象与ContentProvider有什么关系?

2、我们是如何得到ContentProvider中的内容呢?

2.1、ContentResolver与ContentProvider的关系,先来看看得到ContentResolver的过程:

@ContextImpl.java

public ContentResolver getContentResolver() {

return mContentResolver;

}

这里的mContentResolver是在ContextImpl的init中完成初始化的:

final void init(Resources resources, ActivityThread mainThread, UserHandle user) {

mPackageInfo = null;

mBasePackageName = null;

mResources = resources;

mMainThread = mainThread;

//mContentResolver被初始化为ApplicationContentResolver对象

mContentResolver = new ApplicationContentResolver(this, mainThread, user);

mUser = user;

}

mContentResolver被初始化为ApplicationContentResolver对象,我们再来看ApplicationContentResolver这个类,他是ContextImpl的内部类:

private static final class ApplicationContentResolver extends ContentResolver {

public ApplicationContentResolver( Context context, ActivityThread mainThread, UserHandle user) { }

protected IContentProvider acquireProvider(Context context, String auth) { }

protected IContentProvider acquireExistingProvider(Context context, String auth) { }

public boolean releaseProvider(IContentProvider provider) { }

protected IContentProvider acquireUnstableProvider(Context c, String auth) { }

public boolean releaseUnstableProvider(IContentProvider icp) { }

public void unstableProviderDied(IContentProvider icp) { }

}

他提供了得到IContentProvider的各种方法,而且继承自ContentResolver类,我们来看这个类的属性:

@ContentResolver.java

public abstract class ContentResolver { }

可以看到,ContentResolver并没有继承任何的类或者接口,因此,我们可以认为,从继承关系上来讲,ContentResolver与ContentProvider没有任何关系。

那么我们是如何最终得到ContentProvider的呢?

2.2、如何通过ContentResolver得到ContentProvider

下面我们来解答第二个疑问,我们是如何通过ContentResolver去查询到ContentProvider中的内容呢?

虽然我们知道这两者从继承关系上并没有什么联系,但是ContentResolver的内部却出现了我们熟悉的一些方法,包括:

public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {}

public final int delete(Uri url, String where, String[] selectionArgs){}

public final int update(Uri uri, ContentValues values, String where, String[] selectionArgs) {}

public final Uri insert(Uri url, ContentValues values){}

这就说明,两者在功能上一定有联系,下面我们从最开始的delete操作去分析,看两者究竟有什么关系。

回到最初的调用地点,当我们需要通过ContentProvider去delete一项数据时,就会调用getContentResolver().delete()方法,上面分析道,getContentResolver()得到的就是ApplicationContentResolver的对象,而ApplicationContentResolver又继承自ContentResolver。因此,delete的操作就落在ContentResolver中:

@ContentResolver.java

public final int delete(Uri url, String where, String[] selectionArgs)

{

IContentProvider provider = acquireProvider(url);

try {

int rowsDeleted = provider.delete(url, where, selectionArgs);

} catch (RemoteException e) {

} finally {

}

}

在这一步中,我们先通过acquireProvider()得到IContentProvider对象,然后调用IContentProvider对象的delete方法进行操作。那么,这里是如何通过acquireProvider()得到IContentProvider对象的呢?

public final IContentProvider acquireProvider(Uri uri) {

//安全确认

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

return null;

}

final String auth = uri.getAuthority();

if (auth != null) {

//继续调用

return acquireProvider(mContext, auth);

}

return null;

}

继续看:

protected abstract IContentProvider acquireProvider(Context c, String name);

这里竟然遇到了抽象的acquireProvider,说明这个方法需要到子类中实现,那么我们就去ApplicationContentResolver中去看看:

@ContextImpl.java

private static final class ApplicationContentResolver extends ContentResolver {

//果然找到了acquireProvider方法

protected IContentProvider acquireProvider(Context context, String auth) {

return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);

}

}

我们确实在ApplicationContentResolver中找到了acquireProvider()方法,而且发现acquireProvider方法所提供的返回值是来自于mMainThread对象的acquireProvider方法。

那么,这个mMainThread是哪里来的呢?

2.3、寻找mMainThread对象来历

在ActivityThread中创建一个Activity之后,就会调用ActivityThread中的createBaseContextForActivity()方法,为当前的Activity创建Context对象和mMainThread对象:

@ActivityThread.java

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {

//这里就是要创建Context对象的地方

ContextImpl appContext = new ContextImpl();

//并把当前ActivityThread对象传递给ContextImpl的init方法中

appContext.init(r.packageInfo, r.token, this);

}

此时将会调用ContextImpl中的init方法:

@ContextImpl.java

//这里的mainThread就是ActivityThread对象

final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {

init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle());

}

final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, Resources container, String basePackageName, UserHandle user){

//mMainThread就是ActivityThread对象

mMainThread = mainThread;

mContentResolver = new ApplicationContentResolver(this, mainThread, user);

}

这个过程我们发现,mMainThread就是ActivityThread对象,因此在2.2中我们介绍的mMainThread.acquireProvider()相当于:

ActivityThread.acquireProvider();我们继续看:

@ActivityThread.java

public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {

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) {

}

holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);

return holder.provider;

}

这里可以看到,ActivityThread中存在一个HashMap用来缓存所有的provider。每一次对provider的请求,都会先通过acquireExistingProvider()查询是否已经被缓存,如果没有缓存,就去创建该provider的ContentProviderHolder对象,同时缓存下来方便下次调用。

我们假设当前没有ContactsProvider的缓存,那么将会通过ActivityManagerNative.getDefault().getContentProvider()创建该provider,下面我们来分析这个创建的过程。

2.4、ActivityThread创建ContentProvider的过程。

前面说过,ActivityThread创建ContentProvider是通过以下方式实现的:

ActivityManagerNative.getDefault().

getContentProvider(getApplicationThread(), auth, userId, stable);

这个过程可以分为两步:

1、我们来看通过ActivityManagerNative.getDefault()所得到的对象;

2、我们再来分析这个对象的getContentProvider方法。

2.4.1、ActivityManagerNative对象。

我们先介绍一下ActivityManagerService服务。

当系统启动后,在SystemServer中就会将一些重要的Server启动起来,其中就包括ActivityManagerService:

@SystemServer.java

public void run() {

//启动ActivityManagerService

context = ActivityManagerService.main(factoryTest);

//注册ActivityManagerService

ActivityManagerService.setSystemProcess();

}

上面调用ActivityManagerService.main方法的结果就是启动ActivityManagerService,然后调用setSystemProcess把ActivityManagerService注册给系统:

@ActivityManagerService.java

public static void setSystemProcess() {

try {

ActivityManagerService m = mSelf;

//将自己注册为“activity”的Server

ServiceManager.addService("activity", m, true);

ServiceManager.addService("meminfo", new MemBinder(m));

ServiceManager.addService("gfxinfo", new GraphicsBinder(m));

ServiceManager.addService("dbinfo", new DbBinder(m));

} catch (PackageManager.NameNotFoundException e) {

}

}

我们再来看ActivityManagerService的继承关系:

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {}

说明这个Server继承自ActivityManagerNative,而且父类主要完成一些Binder的操作。

这样我们就对ActivityManagerNative的结构有了大致的了解,根据Binder通讯机制,如果我们跨进程去请求ActivityManagerService的服务时,就会调用他的asBinder()方法,并把他的IBinder对象返回给客户端使用。

接着我们上面的分析,我们在2.4节中把创建ContentProvider分为两步,第一步就是得到ActivityManagerNative.getDefault()对象,现在我们来看源码:

@ActivityManagerNative.java

static public IActivityManager getDefault() {

return gDefault.get();

}

我们看,调用ActivityManagerNative的getDefault()方法的结果就是得到gDefault对象里面的数据,那么gDefault里面究竟放着怎样的数据呢?我们来看他的定义:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {

protected IActivityManager create() {

IBinder b = ServiceManager.getService("activity");

IActivityManager am = asInterface(b);

return am;

}

};

原来,在gDefault变量的初始化过程中(create),完成了两步重要的操作:

1、通过getService("activity")得到ActivityManagerService的远程Binder;

2、利用得到的Biner对象通过asInterface()方法,得到这个服务的远程代理;

对于得到Binder对象,这是由Binder系统决定的,我们无需多看,我们来看一下如何通过Binder得到服务的远程代理:

static public IActivityManager asInterface(IBinder obj) {

if (obj == null) {

return null;

}

IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);

if (in != null) {

return in;

}

return new ActivityManagerProxy(obj);

}

通过asInterface() 的细节我们发现,我们得到的远程代理对象就是ActivityManagerProxy对象。也就是说我们当初的:

ActivityManagerNative.getDefault().

getContentProvider( getApplicationThread(), auth, userId, stable);

其实相当于:ActivityManagerProxy.getContentProvider(getApplicationThread(), auth, userId, stable);;

现在我们已经弄明白了2.4中提到的第一步操作,下面我们来分析第二部操作。

2.4.2、代理对象的getContentProvider操作

这一步当然是在ActivityManagerProxy类中发生的:

@ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager{

public ContentProviderHolder getContentProvider(IApplicationThread caller,

String name, int userId, boolean stable) throws RemoteException {

Parcel data = Parcel.obtain();

Parcel reply = Parcel.obtain();

data.writeInterfaceToken(IActivityManager.descriptor);

data.writeStrongBinder(caller != null ? caller.asBinder() : null);

data.writeString(name);

data.writeInt(userId);

data.writeInt(stable ? 1 : 0);

//向ActivityManagerNative发送请求

mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);

reply.readException();

int res = reply.readInt();

ContentProviderHolder cph = null;

if (res != 0) {

cph = ContentProviderHolder.CREATOR.createFromParcel(reply);

}

data.recycle();

reply.recycle();

return cph;

}

}

我们看到,在getContentProvider的过程中,ActivityManagerProxy把请求通过mRemote发送给远端的ActivityManagerNative去处理,请求码为GET_CONTENT_PROVIDER_TRANSACTION。

而ActivityManagerNative需要在onTransact()中去接收请求:

@ActivityManagerNative.java

public abstract class ActivityManagerNative extends Binder implements IActivityManager{

//处理各种请求

public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

switch (code) {

case GET_CONTENT_PROVIDER_TRANSACTION: {

data.enforceInterface(IActivityManager.descriptor);

IBinder b = data.readStrongBinder();

IApplicationThread app = ApplicationThreadNative.asInterface(b);

String name = data.readString();

int userId = data.readInt();

boolean stable = data.readInt() != 0;

//调用ActivityManagerService的getContentProvider方法

ContentProviderHolder cph = getContentProvider(app, name, userId, stable);

reply.writeNoException();

if (cph != null) {

reply.writeInt(1);

cph.writeToParcel(reply, 0);

} else {

reply.writeInt(0);

}

return true;

}

}

}

}

在onTransact中把该请求又发送给了真正的服务端ActivityManagerService.getContentProvider():

@ActivityManagerService.java

public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) {

return getContentProviderImpl(caller, name, null, stable, userId);

}

继续看服务端的操作:

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {

ContentProviderRecord cpr;

ContentProviderConnection conn = null;

ProviderInfo cpi = null;

synchronized(this) {

//查询缓存中是否已经存在该ContentProviderRecord

cpr = mProviderMap.getProviderByName(name, userId);

boolean providerRunning = cpr != null;

if (providerRunning) {

//如果该provider已经被运行过

//得到该ContentProviderRecord的ProviderInfo

cpi = cpr.info;

if (r != null && cpr.canRunHere(r)) {

//直接将ContentProviderHolder传给客户端即可

ContentProviderHolder holder = cpr.newHolder(null);

//清空其provider,由客户端自己去初始化provider的对象

holder.provider = null;

return holder;

}

}

if (!providerRunning) {

//当前没有运行

//加载该provider的包,得到ProviderInfo

cpi = AppGlobals.getPackageManager().resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);

//为当前provider创建ContentProviderRecord

ComponentName comp = new ComponentName(cpi.packageName, cpi.name);

cpr = mProviderMap.getProviderByClass(comp, userId);

//缓存当前的ContentProviderRecord

mProviderMap.putProviderByName(name, cpr);

conn = incProviderCountLocked(r, cpr, token, stable);

}

}

//将ContentProviderHolder传给客户端

return cpr != null ? cpr.newHolder(conn) : null;

}

在上面这个过程中,我们发现,在ActivityManagerService中有存在着一个mProviderMap的变量用于保存当前系统中所有的provider,其中每一项都是一个ContentProviderRecord型的数据,通过这个数据可以完成两个重要作用:

1、通过ContentProviderRecord.info可以得到当前provider的详细信息,包括该provider的authority、readPermission、writePermission、uriPermissionPatterns等重要信息;

2、可以通过ContentProviderRecord.newHolder()方法,生成一个针对当前provider的详细信息,我们需要把这些信息打包为Holder传递给ActivityThread使用。

我们再回到ActivityThread中的acquireProvider()里面:

public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {

final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);

IActivityManager.ContentProviderHolder holder = null;

try {

//得到ContentProviderHolder对象

holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);

} catch (RemoteException ex) {

}

//用provider信息去初始化当前的provider

holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);

//得到provider对象

return holder.provider;

}

在前面的过程中,我们通过ActivityManagerService得到了ContentProviderHolder对象,该对象是对provider的详细描述,下面我们需要用这些描述在installProvider()方法中开启provider,并获得该provider的代理对象。

private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {

ContentProvider localProvider = null;

IContentProvider provider;

if (holder == null || holder.provider == null) {

//当前客户端没有得到过该provider,因此需要获得该provider远程代理

Context c = null;

ApplicationInfo ai = info.applicationInfo;

if (context.getPackageName().equals(ai.packageName)) {

//如果要获得的provider就在当前发出请求的客户端

c = context;

} else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) {

c = mInitialApplication;

} else {

try {

//为要创建的provider创建Context对象

c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE);

} catch (PackageManager.NameNotFoundException e) {

}

}

try {

final java.lang.ClassLoader cl = c.getClassLoader();

//载入provider的类

localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();

//得到该provider的IContentProvider对象

provider = localProvider.getIContentProvider();

localProvider.attachInfo(c, info);

} catch (java.lang.Exception e) {

}

} else {

//如果已经为该客户端创建过相应的provider,直接返回即可

provider = holder.provider;

}

IActivityManager.ContentProviderHolder retHolder;

synchronized (mProviderMap) {

IBinder jBinder = provider.asBinder();

//重新构建ContentProviderHolder类型的retHolder

if (localProvider != null) {

ComponentName cname = new ComponentName(info.packageName, info.name);

ProviderClientRecord pr = mLocalProvidersByName.get(cname);

if (pr != null) {

provider = pr.mProvider;

} else {

//得到ContentProvider的远程代理对象

holder = new IActivityManager.ContentProviderHolder(info);

holder.provider = provider;

holder.noReleaseNeeded = true;

pr = installProviderAuthoritiesLocked(provider, localProvider, holder);

mLocalProviders.put(jBinder, pr);

mLocalProvidersByName.put(cname, pr);

}

retHolder = pr.mHolder;

} else {

ProviderRefCount prc = mProviderRefCountMap.get(jBinder);

if (prc != null) {

if (!noReleaseNeeded) {

incProviderRefLocked(prc, stable);

try {

ActivityManagerNative.getDefault().removeContentProvider( holder.connection, stable);

} catch (RemoteException e) {

}

}

} else {

ProviderClientRecord client = installProviderAuthoritiesLocked(provider, localProvider, holder);

if (noReleaseNeeded) {

prc = new ProviderRefCount(holder, client, 1000, 1000);

} else {

prc = stable

? new ProviderRefCount(holder, client, 1, 0)

: new ProviderRefCount(holder, client, 0, 1);

}

mProviderRefCountMap.put(jBinder, prc);

}

retHolder = prc.holder;

}

}

return retHolder;

}

我们清晰的看到,在installProvider的方法中,我们用ActivityManagerService中得到的ContentProvider信息,去加载该ContentProvider(localProvider),并调用他的getIContentProvider()方法得到该provider的代理对象。

然后我们再回到ActivityThread中的acquireProvider():

public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {

final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);

IActivityManager.ContentProviderHolder holder = null;

try {

//得到ContentProviderHolder对象

holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);

} catch (RemoteException ex) {

}

//用provider信息去初始化当前的provider

holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);

//将得到provider代理对象返回给客户端调用

return holder.provider;

}

经过上面的分析,我们从最初的getContentResolver()一步步的分析,经过ContextImpl、ActivityThread、ActivityManagerNative、ActivityManagerService,最终得到了ContentProvider的代理对象。

三、ContentProvider调用分析

在上面一节中我们对getContentResolver()的过程进行分析,发现这样操作的结果不仅可以载入需要的ContentProvider(如果当前ContentProvider还没有被载入),并且调用了该ContentProvider的getIContentProvider()方法。这一节我们就要从这个方法入手,看看如何通过这个方法得到ContentProvider对象,又如何通过该对象传递对数据库的操作。

我们先来看一下通过getIContentProvider()方法得到的究竟是什么对象。

@ContentProvider.java

public IContentProvider getIContentProvider() {

return mTransport;

}

这里得到的只是IContentProvider类型的mTransport变量,而这个变量的来历呢?

private Transport mTransport = new Transport();

这就说明,通过getIContentProvider()的方法得到的只是Transport对象,他是ContentProvider的内部类:

class Transport extends ContentProviderNative {

ContentProvider getContentProvider() { }

public String getProviderName() { }

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) { }

public Uri insert(Uri uri, ContentValues initialValues) { }

public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { }

public int delete(Uri uri, String selection, String[] selectionArgs) { }

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { }

}

而且我们发现这个内部类提供了用于查询数据库的各项操作。那么当我们进行delete操作的时候呢?

public int delete(Uri uri, String selection, String[] selectionArgs) {

enforceWritePermission(uri);

return ContentProvider.this.delete(uri, selection, selectionArgs);

}

既然Transport内部把delete操作传递给了ContentProvider去操作,那么我们就来看看ContentProvider本身对delete()的处理:

public abstract int delete(Uri uri, String selection, String[] selectionArgs);

这里我们遇到了抽象的方法,也就是说,delete操作的具体细节需要在ContentProvider的子类中实现了,这也符合ContentProvider框架的设计理念,即:ContentProvider负责抽象部分的表述,具体的操作需要各自private自己去实现。

我们此时来看一下ContentProvider本身提供了哪些重要的方法:

public abstract class ContentProvider implements ComponentCallbacks2 {

private Transport mTransport = new Transport();

//构造函数

public ContentProvider() { }

//权限相关操作

protected final void setReadPermission(String permission) { }

public final String getReadPermission() { }

protected final void setWritePermission(String permission) { }

public final String getWritePermission() { }

//增、删、改、查操作。

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

public abstract Uri insert(Uri uri, ContentValues values);

public abstract int delete(Uri uri, String selection, String[] selectionArgs);

public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);

public IContentProvider getIContentProvider() { }

public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { }

}

从ContentProvider提供的方法我们发现,除了权限管理类的方法外,其他的就是一些与delete类似的、与数据库处理相关的抽象方法。

此时我们结合Transport来分析不难发现,这个Transport对象作为ContentProvider的代理,可以对此对象发起各项请求。该代理得到请求后,就会把请求“转发”给ContentProvider本身。

结合上一节我们分析的内容,我们可以总结如下:

我们在应用层调用getContentResolver().delete()的操作,将会调用到ContentResolver对象的delete操作,而ContentResolver对象就相当于通过getIContentProvider()得到的Transport对象,而Transport对象作为ContentProvider的代理将会把各项请求转移到ContentProvider中,因此就调用到ContentProvider的delete方法。

getContentResolver==>ContentResolver==>Transport==>ContentProvider

四、ContentProvider到ContactsProvider

4.1、ContactsProvider综览

经过上面的过程,我们把操作转移到了ContentProvider中,接下来我们需要借助具体的provider来继续分析,我们挑选联系人数据库(ContactsProvider)作为示例来研究。

联系人数据库源码位于\packages\providers\ContactsProvider\中,我们先来看一下他的AndroidManifest.xml文件:

@AndroidManifest.xml

<provider android:name="ContactsProvider2"

android:authorities="contacts;com.android.contacts"

android:label="@string/provider_label"

android:multiprocess="false"

android:exported="true"

android:readPermission="android.permission.READ_CONTACTS"

android:writePermission="android.permission.WRITE_CONTACTS">

<path-permission

android:pathPrefix="/search_suggest_query"

android:readPermission="android.permission.GLOBAL_SEARCH" />

<path-permission

android:pathPrefix="/search_suggest_shortcut"

android:readPermission="android.permission.GLOBAL_SEARCH" />

<path-permission

android:pathPattern="/contacts/.*/photo"

android:readPermission="android.permission.GLOBAL_SEARCH" />

<grant-uri-permission android:pathPattern=".*" />

</provider>

这段声明告诉系统该provider的name、authorities、permission等信息,简单来说,这个数据库的名字叫做ContactsProvider2,可以通过contacts或者com.android.contacts的前缀来匹配,而且访问这个数据库需要相应的权限READ_CONTACTS、WRITE_CONTACTS等。

4.2、ContactsProvider结构

ContactsProvider结构中涉及到五个重要的类:ContentProvider、SQLiteTransactionListener、AbstractContactsProvider、ContactsProvider2、ProfileProvider。下面我们先简单说一下他们的关系。

ContactsProvider在ContentProvider的基础上与SQLiteTransactionListener结合共同组件了AbstractContactsProvider,这是ContactsProvider最基础的类,然后在AbstractContactsProvider的基础上,扩展出来了ContactsProvider2和ProfileProvider这两个类,如下图所示:

接下来我们来分别介绍这五个类的作用。

4.2.1、ContactsProvider

这个不用多说,是系统提供的ContactsProvider架构,里面遗留了对数据库操作的接口,需要子类去实现。

4.2.2、SQLiteTransactionListener

这是一个接口,里面内容也比较简单,只有3个方法:

[java] view plaincopy

public interface SQLiteTransactionListener {

/**

* Called immediately after the transaction begins.

*/

void onBegin();

/**

* Called immediately before commiting the transaction.

*/

void onCommit();

/**

* Called if the transaction is about to be rolled back.

*/

void onRollback();

}

从注释中可以看出,他主要提供与事务处理相关的回调方法,其中onBegin是事务开始处理之后时调用的回调函数,onCommit是事务提交之后的回调函数,onRollback是事务回滚时的回调函数,由此推断,在ContactsProvider中使用了事务的方式对数据库进行操作。

4.2.3、AbstractContactsProvider

这是ContactsProvider结构中最底层的类,我们来看一下他内部主要的方法:

public abstract class AbstractContactsProvider extends ContentProvider implements SQLiteTransactionListener {

public SQLiteOpenHelper getDatabaseHelper() { }

public Uri insert(Uri uri, ContentValues values) { }

public int delete(Uri uri, String selection, String[] selectionArgs) { }

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { }

public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) { }

private ContactsTransaction startTransaction(boolean callerIsBatch) { }

private void endTransaction(boolean callerIsBatch) { }

protected abstract SQLiteOpenHelper getDatabaseHelper(Context context);

protected abstract ThreadLocal<ContactsTransaction> getTransactionHolder();

protected abstract Uri insertInTransaction(Uri uri, ContentValues values);

protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

protected abstract int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs);

protected abstract void notifyChange();

}

这些方法都很好理解,均是对数据库的各项操作。还记得我们在分析ContentProvider的delete操作时提到,ContentProvider把对数据库的各项操作放到子类中处理,对当前环境来说,就是需要在AbstractContactsProvider中处理的,因此delete的操作就应该调用的这里:

public int delete(Uri uri, String selection, String[] selectionArgs) {

//开始事务操作

ContactsTransaction transaction = startTransaction(false);

try {

//用事务进行delete的操作

int deleted = deleteInTransaction(uri, selection, selectionArgs);

if (deleted > 0) {

transaction.markDirty();

}

transaction.markSuccessful(false);

return deleted;

} finally {

endTransaction(false);

}

}

继续看deleteInTransaction的实现:

protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

这仍然是个虚函数,具体定义需要留给子类去实现。

到这里我们发现,在AbstractContactsProvider中把insert、delete、update的操作转换成了事务的处理方式XXXInTransaction,并且把具体的实现留给了子类,这里的子类就是ContactsProvider2和ProfileProvider。也就是说,AbstractContactsProvider的作用就是把对数据库的操作转换成事务的处理方式,至于具体的事务操作,需要在其子类中实现。

另外,我们注意到,所转换的只是insert、delete、update操作,而没有query的操作,也就是说,在ContentProvider中的query操作直接遗留给了子类的子类去实现,而跨过了AbstractContactsProvider的转换。这就说明,query的操作并不需要转换成事务的处理方式。

4.2.4、ProfileProvider

我们现在来看ProfileProvider的结构:

public class ProfileProvider extends AbstractContactsProvider {

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

protected Uri insertInTransaction(Uri uri, ContentValues values){}

protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}

protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs){}

public void onBegin() { }

public void onCommit() { }

public void onRollback() { }

}

我们从ProfileProvider的结构看出,他具备独立的query操作,以及插入、删除、更新的事务操作,以及事务相关的回调函数,可以说,他具备了完整的数据访问、修改能力。但是他的作用呢?

这个问题我们待会儿就会明白。

4.2.5、ContactsProvider2

这是ContactsProvider中最重要也是最上层的类,当初我们在AndroidManifest中只对他进行了注册。

我们来看一下他里面重要的方法:

public class ContactsProvider2 extends AbstractContactsProvider implements OnAccountsUpdateListener {

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

public int delete(Uri uri, String selection, String[] selectionArgs) {}

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}

public Uri insert(Uri uri, ContentValues values) {}

protected Uri insertInTransaction(Uri uri, ContentValues values) {}

protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}

protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {}

}

与ProfileProvider类似,他也提供了完整的数据访问、修改能力。

五、ContactsProvider与SQLite

我们需要明白一点,ContentProvider的底层仍然依靠SQLite来实现的,ContentProvider只是将SQLite的操作进行了封装,更容易操作和理解。

在ContactsProvider的底层设计上,ContactsDatabaseHelper承担着与SQLite直接沟通的角色,在此之上又有差异化扩展了ProfileDatabaseHelper这个类。因此可以认为,在ContactsProvider的底层有两个与SQLite的帮助类。先来看一下他们的结构:

public class ProfileDatabaseHelper extends ContactsDatabaseHelper {}

public class ContactsDatabaseHelper extends SQLiteOpenHelper {}

继承关系如下:

这两个SQLiteOpenHelper类均是在ContactsProvider2的onCreate()时被初始化的:

public boolean onCreate() {

super.onCreate();

return initialize();

}

private boolean initialize() {

//初始化ContactsDatabaseHelper

mContactsHelper = getDatabaseHelper(getContext());

mDbHelper.set(mContactsHelper);

//初始化ProfileDatabaseHelper

mProfileHelper = mProfileProvider.getDatabaseHelper(getContext());

return true;

}

我们先看ContactsDatabaseHelper初始化过程:

protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {

return ContactsDatabaseHelper.getInstance(context);

}

@ContactsDatabaseHelper.java

public static synchronized ContactsDatabaseHelper getInstance(Context context) {

if (sSingleton == null) {

//new出一个ContactsDatabaseHelper完成初始化

sSingleton = new ContactsDatabaseHelper(context, DATABASE_NAME, true);

}

return sSingleton;

}

再来看ProfileDatabaseHelper初始化过程:

[java] view plaincopy

protected ProfileDatabaseHelper getDatabaseHelper(Context context) {

return ProfileDatabaseHelper.getInstance(context);

}

public static synchronized ProfileDatabaseHelper getInstance(Context context) {

if (sSingleton == null) {

//new出一个ProfileDatabaseHelper完成初始化

sSingleton = new ProfileDatabaseHelper(context, DATABASE_NAME, true);

}

return sSingleton;

}

因为在ContactsProvider中存在两个“不同”的SQLiteOpenHelper,因此在具体的数据库操作时,需要根据不同需要来切换(switchToXXXMode)不同的SQLiteOpenHelper去操作。切换的过程我们稍后再讲。

既然SQLiteOpenHelper存在两个,配套的,应该就有两个ContentProvider去操作这两个SQLiteOpenHelper,事实确实如此,在这两个SQLite操作类之上,分别搭建了ProfileProvider与ContactsProvider2这两个与ContentProvider相关的类,也就是说,这四者的对应关系类似与下图:

下面我们借助一次delete()操作来看看这两对数据库的操作流向。

5.1、仍然继续delete()

我们不妨再次回顾一下,当我们进行delete操作时,我们调用getContentResolver最终将会调用到ContentProvider中的delete方法,进而调用到ContactsProvider2中的delete方法:

@ContactsProvider2.java

public int delete(Uri uri, String selection, String[] selectionArgs) {

waitForAccess(mWriteAccessLatch);

//权限管理

enforceSocialStreamWritePermission(uri);

//查看是否需要放到ProfileProvider中处理

if (mapsToProfileDb(uri)) {

switchToProfileMode();

//在ProfileProvider中处理

return mProfileProvider.delete(uri, selection, selectionArgs);

} else {

switchToContactMode();

//回到父类中处理delete操作

return super.delete(uri, selection, selectionArgs);

}

}

在delete的过程中,根据mapsToProfileDb()的判断,需要切换两种模式:Profile与Contact模式,这也是我们刚刚讲的,需要根据不同的情况切换不同的SQLiteOpenHelper去操作数据库,我们现在来看一下区分两种模式的依据:

private boolean mapsToProfileDb(Uri uri) {

return sUriMatcher.mapsToProfile(uri);

}

这里是根据给出的uri去sUriMatcher中查找是否有匹配的项,如果有,就认为需要转换到Profile模式去处理,那么sUriMatcher中究竟有哪些项呢?

@ContactsProvider2.java

static {

final UriMatcher matcher = sUriMatcher;

matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", AGGREGATION_SUGGESTIONS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", AGGREGATION_SUGGESTIONS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", CONTACTS_ID_DISPLAY_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", CONTACTS_ID_STREAM_ITEMS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo", CONTACTS_LOOKUP_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", CONTACTS_LOOKUP_ID_DATA);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo", CONTACTS_LOOKUP_ID_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", CONTACTS_LOOKUP_DISPLAY_PHOTO);

//......

}

我们发现,在ContactsContract中定义的URI都在这个MAP中,也就是说,我们用ContactsContract中的URI去操作数据库时,都应该满足mapsToProfileDb的条件。

下面我们分别看这两种情况具体的操作。

5.2、ContactsProvider2的操作

我们先来分析这个数据流操作,再去分析ProfileProvider操作。也就是说我们需要switchToContactMode():

private void switchToContactMode() {

//将mDbHelper切换到mContactsHelper,也就是ContactsDatabaseHelper

mDbHelper.set(mContactsHelper);

mTransactionContext.set(mContactTransactionContext);

mAggregator.set(mContactAggregator);

mPhotoStore.set(mContactsPhotoStore);

mInProfileMode.set(false);

}

这里最重要的操作就是将mDbHelper中内容置换为mContactsHelper,也就是ContactsDatabaseHelper。接下来就是super.delete()的操作,这里的super对ContactsProvider2来说就是AbstractContactsProvider:

@AbstractContactsProvider.java

public int delete(Uri uri, String selection, String[] selectionArgs) {

ContactsTransaction transaction = startTransaction(false);

try {

int deleted = deleteInTransaction(uri, selection, selectionArgs);

transaction.markSuccessful(false);

return deleted;

} finally {

endTransaction(false);

}

}

protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

这个“转换”的操作我们之前分析过,就是把delete操作转换为事务处理的方式,具体操作需要在子类中实现,因此又回到了ContactsProvider2中的deleteInTransaction:

[java] view plaincopy

protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {

//得到SQLiteOpenHelper,当前是ContactsDatabaseHelper

final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();

//根据当前uri匹配结果

final int match = sUriMatcher.match(uri);

switch (match) {

case CONTACTS: {

invalidateFastScrollingIndexCache();

return 0;

}

case CONTACTS_ID: {

invalidateFastScrollingIndexCache();

long contactId = ContentUris.parseId(uri);

return deleteContact(contactId, callerIsSyncAdapter);

}

default: {

mSyncToNetwork = true;

return mLegacyApiSupport.delete(uri, selection, selectionArgs);

}

}

}

这里我们假设匹配的是CONTACTS_ID:

private int deleteContact(long contactId, boolean callerIsSyncAdapter) {

//得到SQLiteOpenHelper

final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();

mSelectionArgs1[0] = Long.toString(contactId);

//先查询相关信息

Cursor c = db.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, RawContacts.CONTACT_ID + "=?", mSelectionArgs1, null, null, null);

try {

while (c.moveToNext()) {

long rawContactId = c.getLong(0);

markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);

}

} finally {

c.close();

}

mProviderStatusUpdateNeeded = true;

//删除SQLite

return db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);

}

在deleteContact的过程中,要先得到可用的SQLiteDatabase,当前来说就是得到ContactsDatabaseHelper的SQLiteDatabase,然后查询数据库得到Cursor,并遍历每一项标记其删除的标记,最后再调用SQLiteDatabase的delete()方法将该条记录删除。

我们详细看一下SQLiteDatabase的delete()过程:

@SQLiteDatabase.java

public int delete(String table, String whereClause, String[] whereArgs) {

acquireReference();

try {

//构建SQL语句

SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table + (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);

try {

//执行删除命令

return statement.executeUpdateDelete();

} finally {

statement.close();

}

} finally {

releaseReference();

}

}

我们看到,delete操作中,先通过SQLiteStatement生成SQL语句(DELETE FROM XXX WHERE XXX),然后通过executeUpdateDelete()方法去应用该SQL操作,从而完成delete的操作。

到这里,我们终于完成了从ContentProvider到SQLite的“历程”。

5.3、ProfileProvider的操作

首先要切换数据库为ProfileDatabaseHelper:

private void switchToProfileMode() {

//为mDbHelper设置ProfileDatabaseHelper

mDbHelper.set(mProfileHelper);

mTransactionContext.set(mProfileTransactionContext);

mAggregator.set(mProfileAggregator);

mPhotoStore.set(mProfilePhotoStore);

mInProfileMode.set(true);

}

然后进行删除动作:

mProfileProvider.delete(uri, selection, selectionArgs);

也就是调用ProfileProvider中的delete方法,但是在ProfileProvider没有找到delete方法,我们只能去其父类AbstractContactsProvider中调用delete():

@AbstractContactsProvider.java

public int delete(Uri uri, String selection, String[] selectionArgs) {

ContactsTransaction transaction = startTransaction(false);

try {

//把delete转换为事务的处理方式

int deleted = deleteInTransaction(uri, selection, selectionArgs);

if (deleted > 0) {

transaction.markDirty();

}

transaction.markSuccessful(false);

return deleted;

} finally {

endTransaction(false);

}

}

protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

经过AbstractContactsProvider的“转换”,将delete操作转换到子类中的deleteInTransaction():

@ProfileProvider.java

protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {

enforceWritePermission();

useProfileDbForTransaction();

return mDelegate.deleteInTransaction(uri, selection, selectionArgs);

}

这里的mDelegate就是ContactsProvider2本身,因此在ProfileProvider中扰了一圈,又回到了ContactsProvider2中的deleteInTransaction(),而这个方法我们在5.2节已经介绍过详细的流程。

六、总结

现在我们回顾一下整个流程:

1、当我们调用getContentResolver().delete()后,将会通过getContentResolver()得到ContentResolver对象,然后调用该对象的delete()方法。

2、在ContentResolver中,会通过acquireProvider()的方法得到IContentProvider对象,而这个对象的获取首先需要ActivityThread中向ActivityManagerService申请的ContentProvider的详细信息(ContentProviderHolder),然后利用这个Holder去得到(getIContentProvider)ContentProvider的远程代理对象(Transport对象)。

3、拿到这个对象之后,调用其delete方法,该方法将会由ContentProvider传递给其子类(AbstractContactsProvider),并在子类中将delete操作转换为事务处理的方式(deleteInTransaction),AbstractContactsProvider中虽然将处理方式转换成事务的方式,但是却没有具体的实现,而是把具体的操作留给其子类(ContactsProvider2)完成。

4、ContactsProvider2在实现过程中将会用相应的SQLiteOpenHelper去把操作转换成具体的SQLite语句并执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: