ContentResolver提供了一个requestSync函数,用于发起一次数据同步请求。在本例中,该函数的调用方法如下:

~~~

Account emailSyncAccount = newAccount("fanping.deng@gmail",

"com.google");

String emailAuthority ="com.android.email.provider";

Bundle emailBundle = new Bundle();

......//为emailBundle添加相关的参数。这些内容和具体的同步服务有关

//发起Email同步请求

ContentResolver.requesetSync(emailSyncAccount,emailAuthority,emailBundle);

~~~

1. 客户端发起请求

ContentResolver requestSync的代码如下:

**ContentResolver.java::requestSync**

~~~

public static void requestSync(Account account,String authority,

Bundle extras) {

//检查extras携带的参数的数据类型,目前只支持float、int和String等几种类型

validateSyncExtrasBundle(extras);

try {

//调用ContentService的requestSync函数

getContentService().requestSync(account, authority, extras);

}......

}

~~~

与添加账户(addAccount)相比,客户端发起一次同步请求所要做的工作就太简单了。

下面转战ContentService去看它的requestSync函数。

2. ContentService 的requestSync函数分析

**ContentService.java::requestSync**

~~~

public void requestSync(Account account, Stringauthority, Bundle extras) {

ContentResolver.validateSyncExtrasBundle(extras);

longidentityToken = clearCallingIdentity();

try {

SyncManager syncManager = getSyncManager();

if(syncManager != null) {

//调用syncManager的scheduleSync

syncManager.scheduleSync(account, authority, extras,

0,false);

}

}finally {

restoreCallingIdentity(identityToken);

}

}

~~~

ContentService将工作转交给SyncManager来完成,其调用的函数是scheduleSync。

(1) SyncManager的scheduleSync函数分析

先行介绍的scheduleSync函数非常重要。

~~~

/*

scheduleSync一共5个参数,其作用分别如下。

requestedAccount表明要进行同步操作的账户。如果为空,SyncManager将同步所有账户。

requestedAuthority表明要同步的数据项。如果为空,SyncManager将同步所有数据项。

extras指定同步操作中的一些参数信息。这部分内容后续分析时再来介绍。

delay指定本次同步请求是否延迟执行。单位为毫秒。

onlyThoseWithUnkownSyncableState是否只同步那些处于unknown状态的同步服务。该参数

在代码中没有注释。结合前面对syncable为unknown的分析,如果该参数为true,则

本次同步请求的主要作用就是通知同步服务进行初始化操作

*/

public void scheduleSync(Account requestedAccount,String requestedAuthority,

Bundleextras, long delay,boolean onlyThoseWithUnkownSyncableState)

~~~

关于scheduleSync的代码将分段分析,其相关代码如下:

**SyncManager.java::scheduleSync**

~~~

boopublic void scheduleSync(AccountrequestedAccount,

StringrequestedAuthority, Bundle extras,

long delay, boolean onlyThoseWithUnkownSyncableState)

//判断是否允许后台数据传输

finalboolean backgroundDataUsageAllowed = !mBootCompleted ||

getConnectivityManager().getBackgroundDataSetting();

if (extras== null) extras = new Bundle();

//下面将解析同步服务中特有的一些参数信息,下面将逐条解释

//SYNC_EXTRAS_EXPEDITED参数表示是否立即执行。如果设置了该选项,则delay参数不起作用

//delay参数用于设置延迟执行时间,单位为毫秒

Booleanexpedited = extras.getBoolean(

ContentResolver.SYNC_EXTRAS_EXPEDITED,false);

if (expedited)

delay = -1;

Account[]accounts;

if (requestedAccount != null) {

accounts = new Account[]{requestedAccount};

} ......

//SYNC_EXTRAS_UPLOAD参数设置本次同步是否对应为上传。从本地同步到服务端为Upload,

//反之为download

finalboolean uploadOnly = extras.getBoolean(

ContentResolver.SYNC_EXTRAS_UPLOAD, false);

//SYNC_EXTRAS_MANUAL等同于SYNC_EXTRAS_IGNORE_BACKOFF加

//SYNC_EXTRAS_IGNORE_SETTINGS

final boolean manualSync = extras.getBoolean(

ContentResolver.SYNC_EXTRAS_MANUAL, false);

//如果是手动同步,则忽略backoff和settings参数的影响

if(manualSync) {

//知识点一:SYNC_EXTRAS_IGNORE_BACKOFF:该参数和backoff有关,见下文的解释

extras.putBoolean(

ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);

//SYNC_EXTRAS_IGNORE_SETTINGS:忽略设置

extras.putBoolean(

ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);

}

finalboolean ignoreSettings = extras.getBoolean(

ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS,false);

//定义本次同步操作的触发源,见下文解释

int source;

if(uploadOnly) {

source = SyncStorageEngine.SOURCE_LOCAL;

} else if(manualSync) {

source = SyncStorageEngine.SOURCE_USER;

} else if(requestedAuthority == null) {

source = SyncStorageEngine.SOURCE_POLL;

} else {

source = SyncStorageEngine.SOURCE_SERVER;

}

~~~

在以上代码中,有两个知识点需要说明。

知识点一和backoff有关:这个词不太好翻译。和其相关的应用场景是,如果本次同步操作执行失败,则尝试休息一会再执行,而backoff在这个场景中的作用就是控制休息时间。由以上代码可知,当用户设置了手动(Manual)参数后,就无须对这次同步操作使用backoff模式。

另外,在后续的代码中,我们会发现和backoff有关的数据被定义成一个Paire,即backoff对应两个参数。这两个参数到底有什么用呢?笔者在SyncManager代码中找到了一个函数,其参数的命名很容易理解。该函数是setBackoff,原型如下:

**SyncManager.java::setBackoff**

~~~

public void setBackoff(Account account, StringproviderName,

long nextSyncTime, long nextDelay)

~~~

在调用这个函数时,Pair中的两个参数分别对应nextSyncTime和nextDelay,所以,Pair中的第一个参数对应nextSyncTime,第二个参数对应nextDelay。backoff的计算中实际上存在着一种算法。它是什么呢?读者不妨先研究setBackoff,然后再和我们一起分享。

知识点二和SyncStorageEngine定义的触发源有关。说白了,触发源就是描述该次同步操作是因何而起的。SyncStorageEngine一共定义了4种类型的源,这里笔者直接展示其原文解释:

~~~

/* Enumvalue for a local-initiated sync. */

public static final int SOURCE_LOCAL = 1;

/** Enum value for a poll-based sync (e.g., upon connectionto network)*/

public static final int SOURCE_POLL = 2;

/* Enumvalue for a user-initiated sync. */

public static final int SOURCE_USER = 3;

/* Enumvalue for a periodic sync. */

publicstatic final int SOURCE_PERIODIC = 4;

~~~

触发源的作用主要是为了SyncStorageEngine的统计工作。本节不打算深究这部分内容,感兴趣的读者可在学习完本节后自行研究。

关于scheduleSync下一阶段的工作,代码如下:

**SyncManager.java::scheduleSync**

~~~

//从SyncAdaptersCache中取出所有SyncService信息

final HashSetsyncableAuthorities = new HashSet();

for(RegisteredServicesCache.ServiceInfo

syncAdapter :mSyncAdapters.getAllServices()) {

syncableAuthorities.add(syncAdapter.type.authority);

}

//如果指定了本次同步的authority,则从上述同步服务信息中找到满足要求的SyncService

if(requestedAuthority != null) {

final boolean hasSyncAdapter =

syncableAuthorities.contains(requestedAuthority);

syncableAuthorities.clear();

if(hasSyncAdapter) syncableAuthorities.add(requestedAuthority);

}

finalboolean masterSyncAutomatically =

mSyncStorageEngine.getMasterSyncAutomatically();

for(String authority : syncableAuthorities) {

for(Account account : accounts) {

//取出AuthorityInfo中的syncable状态,如果为1,则syncable为true,

//如果为-1,则状态为unknown

intisSyncable = mSyncStorageEngine.getIsSyncable(

account,authority);

if(isSyncable == 0) continue;//syncable为false,则不能进行同步操作

final RegisteredServicesCache.ServiceInfo

syncAdapterInfo =

mSyncAdapters.getServiceInfo(

SyncAdapterType.newKey(authority, account.type));

......

//有些同步服务支持多路并发同步操作

final boolean allowParallelSyncs =

syncAdapterInfo.type.allowParallelSyncs();

finalboolean isAlwaysSyncable = syncAdapterInfo.type.

isAlwaysSyncable();

//如果该同步服务此时的状态为unknown,而它又是永远可同步的(AlwaysSyncable),

//那么通过setIsSyncable设置该服务的状态为1

if(isSyncable < 0 && isAlwaysSyncable) {

mSyncStorageEngine.setIsSyncable(account, authority, 1);

isSyncable = 1;

}

//如果只操作unknow状态的同步服务,并且该服务的状态不是unknown,则不允许后续操作

if(onlyThoseWithUnkownSyncableState && isSyncable >= 0)

continue;

//如果此同步服务不支持上传,而本次同步又需要上传,则不允许后续操作

if(!syncAdapterInfo.type.supportsUploading() && uploadOnly)

continue;

//判断是否允许执行本次同步操作。如果同步服务状态为unknown,则总是允许发起同步请求,

//因为这时的同步请求只是为了初始化SyncService

boolean syncAllowed = (isSyncable < 0) ||ignoreSettings

|| (backgroundDataUsageAllowed && masterSyncAutomatically

&& mSyncStorageEngine.getSyncAutomatically(

account,authority));

......

//取出对应的backoff参数

Pair backoff = mSyncStorageEngine.getBackoff(

account,authority);

//获取延迟执行时间

longdelayUntil = mSyncStorageEngine.getDelayUntilTime(

account,authority);

finallong backoffTime = backoff != null ? backoff.first : 0;

if(isSyncable < 0) {

Bundle newExtras = new Bundle();

//如果syncable状态为unknown,则需要设置一个特殊的参数,即

//SYNC_EXTRAS_INITIALIZE,它将通知SyncService进行初始化操作

newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);

scheduleSyncOperation(

new SyncOperation(account, source, authority, newExtras, 0,

backoffTime,delayUntil,allowParallelSyncs));

}

if(!onlyThoseWithUnkownSyncableState)

scheduleSyncOperation(

new SyncOperation(account,source, authority, extras, delay,

backoffTime, delayUntil,allowParallelSyncs));

}//for循环结束

}

}

~~~

scheduleSync函数较复杂,难点在于其策略控制。建议读者反复阅读这部分内容。

scheduleSync最后将构造一个SyncOperation对象,并调用scheduleSyncOperation处理它。scheduleSyncOperation内部会将这个SyncOperation对象保存到mSyncQueue中,然后发送MESSAGE_CHECK_ALARMS消息让mSyncHandler去处理。由于scheduleSyncOperation函数比较简单,因此下面将直接去mSyncHandler的handleMessage函数中分析MESSAGE_CHECK_ALARMS的处理过程。

(2) 处理MESSAGE_CHECK_ALARMS消息

SyncHandler的handleMessage代码如下:

**SyncManager.java::SyncHandler:handleMessage**

~~~

public void handleMessage(Message msg) {

longearliestFuturePollTime = Long.MAX_VALUE;

longnextPendingSyncTime = Long.MAX_VALUE;

try {

waitUntilReadyToRun();

mDataConnectionIsConnected = readDataConnectionState();

//获得WakeLock,防止在同步过程中掉电

mSyncManagerWakeLock.acquire();

//处理周期同步的操作

earliestFuturePollTime= scheduleReadyPeriodicSyncs();

switch (msg.what) {

......

case SyncHandler.MESSAGE_CHECK_ALARMS:

//调用maybeStartNextSyncLocked函数,返回一个时间。见下文解释

nextPendingSyncTime = maybeStartNextSyncLocked();

break;

......

}//switch结束

} finally{

manageSyncNotificationLocked();

/*

将上边函数调用的返回值传递给manageSyncAlarmLocked,该函数内部与

AlarmManagerService交互,其实就是定义一个定时提醒。在Alarm超时后,就会广播

在SyncManager构造函数中定义的那个PendingIntent mSyncAlarmIntent,

而SyncManager收到该广播后又会做对应处理。相关内容读者可自行阅读

*/

manageSyncAlarmLocked(earliestFuturePollTime,nextPendingSyncTime);

mSyncTimeTracker.update();

mSyncManagerWakeLock.release();

}

}

~~~

如以上代码所述,MESSAGE_CHECK_ALARMS消息的处理就是调用maybeStartNextSyncLocked函数。这个函数内容较繁琐,它主要做了以下几项工作。

- 检查SyncQueue中保存的同步操作对象SyncOperation,判断它们对应的同步服务的状态是否为false,如果为false,则不允许执行该同步操作。

- 查询ConnectivityManagerService以判断目标同步服务是否使用了网络。如果该服务当前没有使用网络,则不允许执行该同步操作。

- 判断同步操作对象的执行时间是否已到,如果未到,则不允许执行该操作。

- 将通过上述判断的同步操作对象SyncOperation与当前系统中正在执行的同步操作上下文对象进行比较。系统当前正在执行的同步操作上下文对象对应的数据类是ActiveSyncContext,它是在同步操作对象之上的一个封装,包含了能和同步服务交互的接口。由于并非所有同步服务都支持多路并发同步操作,因此这里需做一些处理,以避免不必要的同步操作。另外,如一个仅对应初始化同步服务的同步操作执行时间过长(由系统属性“sync.max_time_per_sync”控制,默认是5分钟),系统也需做一些处理。

* * * * *

**提示**:maybeStartNextSyncLocked是笔者在本节留给读者自行分析的函数中最难的一个。读者务必阅读完下面的分析后,尝试去研究此函数。

* * * * *

通过上述层层考验后,manageSyncAlarmLocked最后将调用dispatchSyncOperation真正去派发一个同步操作。下面来看dispatchSyncOperation的代码。

**SyncManager.java::dispatchSyncOperation**

~~~

private booleandispatchSyncOperation(SyncOperation op) {

SyncAdapterType syncAdapterType = SyncAdapterType.

newKey(op.authority,op.account.type);

RegisteredServicesCache.ServiceInfo

syncAdapterInfo=

mSyncAdapters.getServiceInfo(syncAdapterType);

......

//构造一个ActiveSyncContext对象,它就是前面提到的同步操作上下文对象

ActiveSyncContextactiveSyncContext =

new ActiveSyncContext(op,

insertStartSyncEvent(op), syncAdapterInfo.uid);

activeSyncContext.mSyncInfo =

mSyncStorageEngine.addActiveSync(activeSyncContext);

// mActiveSyncContexts保存了当前系统中所有的ActiveSyncContext对象

mActiveSyncContexts.add(activeSyncContext);

//为该对象绑定到具体的同步服务上

if(!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {

closeActiveSyncContext(activeSyncContext);

return false;

}

returntrue;

}

~~~

ActiveSyncContext是SyncManager和同步服务交互的关键类,其家族图谱如图8-16所示。

:-: ![](https://img-blog.csdn.net/20150803131747220?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)

图8-16 ActiveSyncContext的 UML类图

图8-16中的ActiveSyncContext和图8-8中的Session非常像。ActiveSyncContext的主要工作包括下面两部分。

- 它将首先通过bindService方式启动SyncService,并在onServiceConnected函数中得到用于和SyncService交互的接口对象,即参与Binder通信的ISyncAdapterBp端。

- ActiveSyncContext是ISyncContext接口的Binder通信的Bn端,它在调用ISyncAdapter的startSync时,会把自己传递给同步服务。同步服务得到的当然是ISyncContext的Bp端对象。当同步服务完成此次同步操作后就会调用ISyncContext 的Bp端对象的onFinished函数以通知ActiveSyncContext同步操作的执行结果。

下面再看第一部分的工作。

(3) ActiveSyncContext派发请求

**SyncManager.java::ActiveSyncContext.bindToSyncAdapter**

~~~

booleanbindToSyncAdapter(RegisteredServicesCache.ServiceInfo info) {

Intentintent = new Intent();

intent.setAction("android.content.SyncAdapter");

//设置目标同步服务的ComponentName

intent.setComponent(info.componentName);

intent.putExtra(Intent.EXTRA_CLIENT_LABEL,

com.android.internal.R.string.sync_binding_label);

intent.putExtra(Intent.EXTRA_CLIENT_INTENT,

PendingIntent.getActivity(

mContext, 0,

new Intent(Settings.ACTION_SYNC_SETTINGS),0));

mBound= true;

//调用bindService启动指定的同步服务

finalboolean bindResult = mContext.bindService(intent, this,

Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND

| Context.BIND_ALLOW_OOM_MANAGEMENT);

if(!bindResult)

mBound = false;

returnbindResult;

}

~~~

当目标SyncService从其onBind函数返回后,ActiveSyncContext的onServiceConnected将被调用,该函数的内部处理流程如下:

**SyncManager.java::ActiveSyncContext.onServiceConnected**

~~~

public void onServiceConnected(ComponentName name,IBinder service) {

Messagemsg = mSyncHandler.obtainMessage();

msg.what= SyncHandler.MESSAGE_SERVICE_CONNECTED;

//构造一个ServiceConnectionData对象,并发送MESSAGE_SERVICE_CONNECTED消息

//给mSyncHandler。第二个参数就是SyncService在onBind函数中返回的ISyncAdapter的

//Binder通信对象。不过在ActiveSyncContext中,它是Bp端

msg.obj= new ServiceConnectionData(this,

ISyncAdapter.Stub.asInterface(service));

mSyncHandler.sendMessage(msg);

}

~~~

**SyncManager.java::SyncHandler.handleMessage**

~~~

case SyncHandler.MESSAGE_SERVICE_CONNECTED: {

ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;

if(isSyncStillActive(msgData.activeSyncContext))

//调用runBoundToSyncAdapter函数处理

runBoundToSyncAdapter(msgData.activeSyncContext,

msgData.syncAdapter);

break;

}

~~~

**SyncManager.java::runBoundToSyncAdapter**

~~~

private void runBoundToSyncAdapter(final ActiveSyncContextactiveSyncContext,

ISyncAdapter syncAdapter) {

activeSyncContext.mSyncAdapter = syncAdapter;

finalSyncOperation syncOperation = activeSyncContext.mSyncOperation;

try {

activeSyncContext.mIsLinkedToDeath = true;

syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);

//调用目标同步服务的startSync函数

syncAdapter.startSync(activeSyncContext, syncOperation.authority,

syncOperation.account, syncOperation.extras);

} ......

}

~~~

对SynManager工作的分析到此为止,下面将分析目标同步服务。

3. EmailSyncAdapterService处理请求

在本例中,目标同步服务位于EmailSyncAdapterService中,先看它通过onBind函数返回给ActiveSyncContext的是什么。

(1) onBind分析

**EmailSyncAdapterService.java::onBind**

~~~

public IBinder onBind(Intent intent) {

//sSyncAdapter是EmailSyncAdapterService的内部类对象,见下文解释

returnsSyncAdapter.getSyncAdapterBinder();

}

~~~

在以上代码中,sSyncAdapter的类型是EmailSyncAdapterService中的内部类SyncAdapterImpl。它的派生关系如图8-17所示。

:-: ![](https://img-blog.csdn.net/20150803131801930?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)

图8-17 SyncAdapterImpl派生关系图

有图8-17可知:

- AbstractThreadSyncAdapter是核心类,其内部有一个成员变量mISyncAdapterIml,该变量用于和ActiveSyncContext交互,是ISyncAdapter Binder通信的Bn端。该对象也是以上代码中onBind函数的返回值。

- SyncThread从Thread派生。从这一点可看出,同步服务将创建工作线程来执行具体的同步操作。AbstractThreadSyncAdapter中的mSyncThreads保存该同步服务中所有的SyncThread对象。

- 同步操作的结果将通过SyncResult返给SyncManager。

再看SyncManager runBoundToSyncAdapter函数最后调用的startSync函数。

(2) startSync分析

在SyncService中,首先被调用的函数是ISyncAdapterImpl的startSync函数,其代码为:

**AbstractThreadedSyncAdapter.java::ISyncAdapterImpl.startSync**

~~~

public void startSync(ISyncContext syncContext,String authority,

Account account,Bundle extras) {

//构造一个SyncContext对象,用于保存上下文信息

finalSyncContext syncContextClient = new SyncContext(syncContext);

booleanalreadyInProgress;

finalAccount threadsKey = toSyncKey(account);

synchronized (mSyncThreadLock) {

//判断是否存在已经在执行的SyncThread

if(!mSyncThreads.containsKey(threadsKey)) {

if (mAutoInitialize

&& extras != null&& extras.getBoolean(

ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {

//一般而言,mAutoInitialize都为true,表示同步服务支持自动初始化

//如果该服务对应的syncable状态为unknown,则重新设置syncable为1

if (ContentResolver.getIsSyncable(account, authority) < 0)

ContentResolver.setIsSyncable(account,authority, 1);

//直接返回,不再做后续的处理,实际上后续的流程是可以继续进行的

syncContextClient.onFinished(new SyncResult());

return;

}

//创建一个新的SyncThread对象

SyncThread syncThread = new SyncThread(

"SyncAdapterThread-" +

mNumSyncStarts.incrementAndGet(),

syncContextClient,authority, account, extras);

mSyncThreads.put(threadsKey, syncThread);

syncThread.start();//启动工作线程

alreadyInProgress = false;

}else {

alreadyInProgress = true;

}

}

if(alreadyInProgress)

syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS);

}

~~~

假如尚未匹配的工作线程(根据account生成一个key作为标示来查找是否已经存在对应的工作线程),SyncService将创建一个SyncThread,其run函数代码是:

**AbstractThreadedSyncAdapter.java::ISyncAdapterImpl.run**

~~~

public void run() {

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

SyncResult syncResult = new SyncResult();

ContentProviderClient provider = null;

try {

if(isCanceled()) return;

//获得同步操作指定的ContentProvider,provider是ContentProviderClient

//类型,用于和目标ContentProvider交互

provider = mContext.getContentResolver().

acquireContentProviderClient(mAuthority);

if (provider != null) {

//调用AbstractThreadedSyncAdapter子类的onPerformSync函数

AbstractThreadedSyncAdapter.this.onPerformSync(mAccount,

mExtras,mAuthority,provider, syncResult);

} else

syncResult.databaseError = true;

}finally {

if (provider != null)

provider.release();

if (!isCanceled()) //通知结果

mSyncContext.onFinished(syncResult);

//工作完成,将该线程从mSyncThreads中移除

synchronized (mSyncThreadLock) {

mSyncThreads.remove(mThreadsKey);

}

}

}

~~~

来看AbstractThreadedSyncAdapter子类实现的onPeroformSync函数,在本例中,子类是SyncAdapterImpl,代码如下:

**EmailSyncAdapterService.java::SyncAdapterImpl.onPerformSync**

~~~

public void onPerformSync(Account account, Bundleextras, String authority,

ContentProviderClient provider,SyncResult syncResult) {

try {

//调用EmailSyncAdapterService performSync完成真正的同步,这部分代码和

//Email业务逻辑相关,此处不再深入研究

EmailSyncAdapterService.performSync(mContext, account, extras,

authority, provider,syncResult);

}......

}

~~~

执行完onPerformSync函数后,ISyncAdapterImpl.run返回前会调用mSyncContext.onFinished函数,向位于SyncManager中的ActiveSyncContext通知同步操作的结果。读者可自行研究这部分内容。

4. ContentResolver requestSync分析总结

总结requestSync的工作流程,如图8-18所示。

:-: ![](https://img-blog.csdn.net/20150803131817211?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)

图8-18 requestSync流程

由图8-18可知,requestSync涉及的对象及调用流程比较繁琐。但从技术上看,则没有什么需要特别注意的地方。

android requestsync,8.4.2 ContentResolver 的requestSync分析相关推荐

  1. ContentResolver.query流程分析

    文章目录 1.Context.getContentResolver() 2.ContentResolver.query() 3.ContentProviderProxy.query() 4.Trans ...

  2. Android Bitmap转换WebP图片导致损坏的分析及解决方案

    Android Bitmap转换WebP图片导致损坏的分析及解决方案 参考文章: (1)Android Bitmap转换WebP图片导致损坏的分析及解决方案 (2)https://www.cnblog ...

  3. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )

    文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...

  4. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )

    文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...

  5. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )

    文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...

  6. 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )

    文章目录 前言 一.热启动与冷启动选择 二.AMS 进程中执行的相关操作 三.通过 Binder 机制转到 ActivityThread 中执行的操作 总结 前言 上一篇博客 [Android 启动过 ...

  7. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 七 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  8. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 六 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  9. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

最新文章

  1. java中图片和字节数组相互转化
  2. 浅说--未将对象引用设置到对象的实例(System.NullReferenceException)
  3. 在word上写博客直接发到CSDN博客
  4. vue项目dist编译文件部署到服务器:页面空白、F5刷新报错404、403报错、等等bug - 总结篇
  5. 关于js数组的六种算法---水桶排序,冒泡排序,选择排序,快速排序,插入排序,希尔排序的理解。...
  6. C语言OJ项目参考(1915) 第几天
  7. 95-50-050-java.nio.channels-NIO-NIO之Channel(通道)
  8. 代码的c++实现_一文带你快速理解FreeRTOS代码规范~
  9. 安卓安装之离线搭建Android Studio开发环境
  10. Hadoop体系结构– YARN,HDFS和MapReduce
  11. 文件io(一)--unix环境高级编程读书笔记
  12. HTTP Get与Post的区别
  13. win10驱动开发——驱动签名
  14. 计算机二级公共基础知识(四)—— 数据库设计基础
  15. 读史可以明智_明智之举:获得满意的广告
  16. delphi的时间Ttime,Tdatetime的信息
  17. Flutter——打包Windows桌面应用(流程)
  18. 【高老师UML软件建模基础】20级云班课习题答案合集
  19. ftp上传工具中文版,有好用的中文版ftp上传工具吗?ftp上传工具中文版
  20. 关于c4d在给模型添加FFD时,遇到拉升FFD里的点,而模型没有任何变化的解决方法

热门文章

  1. 怎么样开启红米S2的Root权限
  2. 小程序 cover-view 字体_字体设计 | 精品字库
  3. md文件自动生成目录[docsify]
  4. (php毕业设计)基于php的校园教务管理系统源码
  5. 模拟器和真机运行都是屏幕上下有黑色的条
  6. 用例图USE CASE中的Actor之眼让你不再雾里看花
  7. 设置WPS文档笔记模版
  8. Spyder 快捷键大全(转)
  9. Redmi K60 Pro参数配置怎么样 性能怎么样 红米 K60 Pro屏幕参数
  10. OpenGL3.0 android环境搭建