基于Andoird 4.2.2的同步框架源代码学习——同步提供端
Android同步框架
同步(synchronization)允许用户将远程数据下载到新的设备上,同时将设备上的帐户数据上传到远端。同步还保证用户能够看到最新的数据。
开发者自然可以通过自己的方式来设计实现同步机制。但是Android系统还是提供了一个可插拔的同步框架。这个框架自动化的执行以下任务:
- 检查网络可用性
- 根据用户设定的选项规划、执行同步
- 重启已经停止的同步
开发者需要向这个框架提供自己定义的同步适配器(Sync adapter)插件。一个sync adapter唯一的与某个servive/content provider相关联。但是后者反过来可以对应多个sync adapter。
SyncAdapter
首先,Android framework尽可能的封装了数据同步相关的共性操作,而将针对特定服务的同步逻辑的具体实现留给了应用程序。这一点具体体现在Android framework提供的
AbstractThreadedSyncAdapter类中提供一个ISyncAdapter接口的本地服务:
并且定义了向外部提供IBinder实例的方法:
其实现方式是通过启动一个独立的线程来发起同步。
这个独立线程的核心就是调用AbstractThreadedSyncAdapter.onPerformSync()方法来执行同步相关的业务逻辑。
AbstractThreadedSyncAdapter抽象类上。对照官方文档中的描述,在应用开发中提供一个自定义的sync adapter,只需要完成下面的几个步骤:
- 扩展AbstractThreadedSyncAdapter抽象类,实现它的onPerformSync()抽象方法
- 在res/xml下创建一个XML文件来描述这个sync adapter
- 在应用中创建一个service,使之处理名为“android.content.SyncAdapter”的动作
详细步骤可见AbstractThreadedSyncAdapter类的参考文档。
这里主要分析一下AbstractThreadedSyncAdapter类本身,也即是sync adapter的共性部分。
看看参与sync adapter调用的类簇:
下面是启动一次同步的序列图:
简要描述一下:
ISyncAdapter
首先,sync adapter的行为通过ISyncAdapter接口来描述:
/** * Interface used to control the sync activity on a SyncAdapter * @hide */ oneway interface ISyncAdapter { /** * Initiate a sync for this account. SyncAdapter-specific parameters may * be specified in extras, which is guaranteed to not be null. * * @param syncContext the ISyncContext used to indicate the progress of the sync. When * the sync is finished (successfully or not) ISyncContext.onFinished() must be called. * @param authority the authority that should be synced * @param account the account that should be synced * @param extras SyncAdapter-specific parameters */ void startSync(ISyncContext syncContext, String authority, in Account account, in Bundle extras); /** * Cancel the most recently initiated sync. Due to race conditions, this may arrive * after the ISyncContext.onFinished() for that sync was called. * @param syncContext the ISyncContext that was passed to {@link #startSync} */ void cancelSync(ISyncContext syncContext); /** * Initialize the SyncAdapter for this account and authority. * * @param account the account that should be synced * @param authority the authority that should be synced */ void initialize(in Account account, String authority); }
AbstractThreadedSyncAdapter类中提供一个ISyncAdapter接口的本地服务:
private class ISyncAdapterImpl extends ISyncAdapter.Stub { public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { ... } public void cancelSync(ISyncContext syncContext) { ... } public void initialize(Account account, String authority) throws RemoteException { ... } }
并且定义了向外部提供IBinder实例的方法:
/** * @return a reference to the IBinder of the SyncAdapter service. */ public final IBinder getSyncAdapterBinder() { return mISyncAdapterImpl.asBinder(); }
ISyncAdapter.startSync()
public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { ... synchronized (mSyncThreadLock) { if (!mSyncThreads.containsKey(threadsKey)) { ... SyncThread syncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); mSyncThreads.put(threadsKey, syncThread); syncThread.start(); ... } ... } ... }
其实现方式是通过启动一个独立的线程来发起同步。
SyncThread
private class SyncThread extends Thread { private final SyncContext mSyncContext; private final String mAuthority; private final Account mAccount; private final Bundle mExtras; private final Account mThreadsKey; ... @Override public void run() { ... try { ... provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); if (provider != null) { AbstractThreadedSyncAdapter.this.onPerformSync(mAccount, mExtras, mAuthority, provider, syncResult); } else { syncResult.databaseError = true; } } ... } ... }
这个独立线程的核心就是调用AbstractThreadedSyncAdapter.onPerformSync()方法来执行同步相关的业务逻辑。
这样,总而言之,外界通过从系统中查找得到特定的Sync adapter service,然后通过绑定到这个service来获取ISyncAdapter服务的代理对象。然后调用代理对象来启动/终止同步操作。代理对象与提供同步实现的应用程序进程进行IPC来发起真正的同步过程。