android.content.AbstractThreadedSyncAdapter
是一个虚类,它主要用于执行Account相关内容(比如Contact)的同步操作。它是对
Account的内容(比如contact)进行同步操作的适配器。
AbstractThreadedSyncAdapter收到同步请求后,将生产一个线程来进行Account指定内容的同步处理。当
AbstractThreadedSyncAdapter
收到
startSync()
请求,如果此时并不是正在进行同步操作,那么将启动一个线程,通过在该线程中调用
AbstractThreadedSyncAdapter
的
AbstractThreadedSyncAdapter
收到
cancelSync()
请求,那么同步操作将被中断,以达到取消同步操作的目的。
onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)
方法来执行同步操作。如果正在进行同步操作时,
android.content.AbstractThreadedSyncAdapter
是一个虚类,我们必须新建一个继续于它的新类,并重写
onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult),
才能使用。
AbstractThreadedSyncAdapte
里面有个继承于
ISyncAdapter.Stub
的内部类,以用来对
AbstractThreadedSyncAdapte
的远程接口调用进行包装。我们可以通过
AbstractThreadedSyncAdapte
的
getIBinder()
方法,返回内部类的IBinder形式,以便对
AbstractThreadedSyncAdapte
进行远程调用。
为了能让系统找到我们自己的对Account内容(比如contact)进行同步操作的适配器
AbstractThreadedSyncAdapte
,我们需要如下定义一个能接受
action为
android.content.SyncAdapter
的Intent的Service,并在Service的
onBind(android.content.Intent)
中调
AbstractThreadedSyncAdapte
的
getSyncAdapterBinder()
返回其用于远程调用的
IBinde
r
接口形式
。
示例1
<intent-filter> <action android:name="android.content.SyncAdapter" /> </intent-filter> <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" />
示例2(来自
SampleSyncAdapter
)
<service
android:name=".syncadapter.SyncService"
android:exported="true">
<intent-filter>
<action
android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
<meta-data
android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
The
android:resource
attribute must point to a resource that looks like:
Service应该有个名为
android.content.SyncAdapter
的
meta-data
,该
meta-data
的
resource
属性所指向的
xml
文件应该说明该Account内容同步适配器
AbstractThreadedSyncAdapter
的
基本显示信息,其语法如下:
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="authority" android:accountType="accountType" android:userVisible="true|false" android:supportsUploading="true|false" android:allowParallelSyncs="true|false" android:isAlwaysSyncable="true|false" android:syncAdapterSettingsAction="ACTION_OF_SETTINGS_ACTIVITY" />
示例3
(来自
SampleSyncAdapter
)
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.example.android.samplesync"
android:supportsUploading="false"
/>
- The
android:contentAuthority
andandroid:accountType
attributes indicate which content authority and for which account types this sync adapter serves.android:contentAuthority表示授权进行同步的内容的类型。比如com.android.contacts。android:accountType表示授权同步的账号的类型。比如示例3中的"com.example.android.samplesync"。又比如,对于google账号是, android:accountType 为“ com.google ”,关于此可以参照《Account简介》。ContentProvider在其AndroidManifest.xml文件中有个android:authorities属性,比如,在ContactsProvider中,是android:authorities="contacts;com.android.contacts"。这里的android:authorities和AbstractThreadedSyncAdapte的android:contentAuthority属性应该相对应。 -
android:userVisible
defaults to true and controls whether or not this sync adapter shows up in the Sync Settings screen. -
android:supportsUploading
defaults to true and if true an upload-only sync will be requested for all syncadapters associated with an authority whenever that authority's content provider does anotifyChange(android.net.Uri, android.database.ContentObserver, boolean)
with syncToNetwork set to true.默认值为true,当我们调用 notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) 时 upload-only sync ,如果 syncToNetwork参数为true的话,将被请求。 -
android:allowParallelSyncs
defaults to false and if true indicates that the sync adapter can handle syncs for multiple accounts at the same time. Otherwise the SyncManager will wait until the sync adapter is not in use before requesting that it sync an account's data.默认为false,用于表示该同步适配器是否支持多个账号同时进行同步,如果不支持, SyncManager只有等一个同步完成后才进行一个账号的同步 -
android:isAlwaysSyncable
defaults to false and if true tells the SyncManager to intialize the isSyncable state to 1 for that sync adapter for each account that is added. -
android:syncAdapterSettingsAction
defaults to null and if supplied it specifies an Intent action of an activity that can be used to adjust the sync adapter's sync settings. The activity must live in the same package as the sync adapter.该属性可以用于指定一个用于对同步操作进行设定的Activity进行启动的intent.注意该activity应该和 SyncAdapter 位于同一个apk包中.
结束。
主要函数
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Context | getContext() | ||||||||||
final IBinder | getSyncAdapterBinder() | ||||||||||
abstract void |
onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
Perform a sync for this account.
| ||||||||||
void |
onSyncCanceled(Thread thread)
Indicates that a sync operation has been canceled.
| ||||||||||
void |
onSyncCanceled()
Indicates that a sync operation has been canceled.
|
AbstractThreadedSyncAdapter源码如下:
package android.content;
import android.accounts.Account;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class
AbstractThreadedSyncAdapter
{
/**
* Kernel event log tag. Also listed in data/etc/event-log-tags.
* @deprecated Private constant. May go away in the next release.
*/
@Deprecated
public static final int LOG_SYNC_DETAILS = 2743;
private final Context mContext;
private final AtomicInteger mNumSyncStarts;
private final ISyncAdapterImpl mISyncAdapterImpl;
// all accesses to this member variable must be synchronized on mSyncThreadLock
private SyncThread mSyncThread;
private final Object mSyncThreadLock = new Object();
private final boolean mAutoInitialize;
/**
* Creates an {@link AbstractThreadedSyncAdapter}.
* @param context the {@link android.content.Context} that this is running within.
* @param autoInitialize if true then sync requests that have
* {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by
* {@link AbstractThreadedSyncAdapter} by calling
* {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it
* is currently set to <0.
*/
public
AbstractThreadedSyncAdapter
(Context context, boolean autoInitialize) {
mContext = context;
mISyncAdapterImpl = new ISyncAdapterImpl();
mNumSyncStarts = new AtomicInteger(0);
mSyncThread = null;
mAutoInitialize = autoInitialize;
}
public Context getContext() {
return mContext;
}
private class
ISyncAdapterImpl
extends
ISyncAdapter.Stub
{
public void
startSync
(ISyncContext syncContext, String authority, Account account,
Bundle extras) {
final SyncContext syncContextClient = new SyncContext(syncContext);
boolean alreadyInProgress;
// synchronize to make sure that mSyncThread doesn't change between when we
// check it and when we use it
synchronized (mSyncThreadLock) {
if
(mSyncThread == null) {
if (mAutoInitialize
&& extras != null
&& extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
if
(ContentResolver.getIsSyncable(account, authority) < 0) {
ContentResolver.setIsSyncable(account, authority, 1);
}
syncContextClient.onFinished(new SyncResult());
return
;
}
mSyncThread = new SyncThread(
"SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(),
syncContextClient, authority, account, extras);
mSyncThread.start();
alreadyInProgress = false;
}
else
{
alreadyInProgress = true;
}
}
// do this outside since we don't want to call back into the syncContext while
// holding the synchronization lock
if
(alreadyInProgress) {
syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS);
}
}
public void
cancelSync
(ISyncContext syncContext) {
// synchronize to make sure that mSyncThread doesn't change between when we
// check it and when we use it
final SyncThread syncThread;
synchronized
(mSyncThreadLock) {
syncThread = mSyncThread;
}
if
(syncThread != null
&& syncThread.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) {
onSyncCanceled();
}
}
public void
initialize
(Account account, String authority) throws RemoteException {
Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
startSync(null, authority, account, extras);
}
}
/**
* The thread that invokes {@link AbstractThreadedSyncAdapter#onPerformSync}. It also acquires
* the provider for this sync before calling onPerformSync and releases it afterwards. Cancel
* this thread in order to cancel the sync.
*/
private class
SyncThread
extends
Thread {
private final SyncContext mSyncContext;
private final String mAuthority;
private final Account mAccount;
private final Bundle mExtras;
private SyncThread(String name, SyncContext syncContext, String authority,
Account account, Bundle extras) {
super(name);
mSyncContext = syncContext;
mAuthority = authority;
mAccount = account;
mExtras = extras;
}
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
if (isCanceled()) {
return;
}
SyncResult syncResult = new SyncResult();
ContentProviderClient provider = null;
try
{
provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority);
if (provider != null) {
AbstractThreadedSyncAdapter.this.onPerformSync(mAccount, mExtras,
mAuthority, provider, syncResult);
}
else
{
syncResult.databaseError = true;
}
}
finally
{
if (provider != null) {
provider.release();
}
if (!isCanceled()) {
mSyncContext.onFinished(syncResult);
}
// synchronize so that the assignment will be seen by other threads
// that also synchronize accesses to mSyncThread
synchronized (mSyncThreadLock) {
mSyncThread = null;
}
}
}
private boolean
isCanceled() {
return
Thread.currentThread().isInterrupted();
}
}
/**
* @return a reference to the IBinder of the SyncAdapter service.
*/
public final
IBinder getSyncAdapterBinder() {
return
mISyncAdapterImpl.asBinder();
}
/**
* Perform a sync for this account. SyncAdapter-specific parameters may
* be specified in extras, which is guaranteed to not be null. Invocations
* of this method are guaranteed to be serialized.
*
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
* @param authority the authority of this sync request
* @param provider a ContentProviderClient that points to the ContentProvider for this
* authority
* @param syncResult SyncAdapter-specific parameters
*/
public abstract void onPerformSync(Account account, Bundle extras,
String authority, ContentProviderClient provider, SyncResult syncResult);
/**
* Indicates that a sync operation has been canceled. This will be invoked on a separate
* thread than the sync thread and so you must consider the multi-threaded implications
* of the work that you do in this method.
*
*/
public void
onSyncCanceled() {
final SyncThread syncThread;
synchronized (mSyncThreadLock) {
syncThread = mSyncThread;
}
if
(syncThread != null) {
syncThread.interrupt();
}
}
}
最后,关于
AbstractThreadedSyncAdapte
的使用请参照google官方的示例程
序
SampleSyncAdapter
。