注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

AbstractThreadedSyncAdapter简介  

2012-03-07 15:12:37|  分类: 开发专题 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
    android.content.AbstractThreadedSyncAdapter是一个虚类,它主要用于执行Account相关内容(比如Contact)的同步操作。它是对 Account的内容(比如contact)进行同步操作的适配器。  AbstractThreadedSyncAdapter收到同步请求后,将生产一个线程来进行Account指定内容的同步处理。当 AbstractThreadedSyncAdapter 收到startSync()请求,如果此时并不是正在进行同步操作,那么将启动一个线程,通过在该线程中调用 AbstractThreadedSyncAdapter onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult) 方法来执行同步操作。如果正在进行同步操作时,  AbstractThreadedSyncAdapter收到cancelSync()请求,那么同步操作将被中断,以达到取消同步操作的目的。
   android.content.AbstractThreadedSyncAdapter是一个虚类,我们必须新建一个继续于它的新类,并重写onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)才能使用。
   AbstractThreadedSyncAdapte里面有个继承于ISyncAdapter.Stub的内部类,以用来对AbstractThreadedSyncAdapte的远程接口调用进行包装。我们可以通过AbstractThreadedSyncAdaptegetIBinder()方法,返回内部类的IBinder形式,以便对AbstractThreadedSyncAdapte进行远程调用。
   为了能让系统找到我们自己的对Account内容(比如contact)进行同步操作的适配器AbstractThreadedSyncAdapte ,我们需要如下定义一个能接受action为 android.content.SyncAdapter的Intent的Service,并在Service的onBind(android.content.Intent)中调AbstractThreadedSyncAdapte getSyncAdapterBinder() 返回其用于远程调用的IBinder接口形式
示例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.SyncAdaptermeta-data,该meta-dataresource属性所指向的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 and android:accountType attributes indicate which content authority and for which account types this sync adapter serves.android:contentAuthority表示授权进行同步的内容的类型。比如com.android.contactsandroid: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:authoritiesAbstractThreadedSyncAdapteandroid: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 a notifyChange(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
ContextgetContext()
final IBindergetSyncAdapterBinder()
abstract voidonPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
Perform a sync for this account.
voidonSyncCanceled(Thread thread)
Indicates that a sync operation has been canceled.
voidonSyncCanceled()
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
  评论这张
 
阅读(1584)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017