ContentService:第二部分数据同步

3.数据同步机制之SyncManager

同步策略

3.1SyncManager的理解

3.1.1SyncAdapterCache类的分析

找出metadata和attribute为指定类型的xml节点数据,并放到存储文件中
/data/system/registered_services/android.content.SyncAdapter.xml

例如davdroid的manifest文件中有以下内容

        
            
                
            

            
        
        
            
                
            

            
        

/data/system/registered_services/android.content.SyncAdapter.xml的文件内容









 


SyncAdapterCache继承自RegisteredServicesCache
并将需要解析和存储的类型传递给了RegisteredServicesCache

public class SyncAdaptersCache extends RegisteredServicesCache {
    private static final String TAG = "Account";

    private static final String SERVICE_INTERFACE = "android.content.SyncAdapter";
    private static final String SERVICE_META_DATA = "android.content.SyncAdapter";
    private static final String ATTRIBUTES_NAME = "sync-adapter";
    private static final MySerializer sSerializer = new MySerializer();

    public SyncAdaptersCache(Context context) {
        super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, sSerializer);
    }

    public SyncAdapterType parseServiceAttributes(Resources res,
            String packageName, AttributeSet attrs) {
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.SyncAdapter);
        try {
            final String authority =
                    sa.getString(com.android.internal.R.styleable.SyncAdapter_contentAuthority);
            final String accountType =
                    sa.getString(com.android.internal.R.styleable.SyncAdapter_accountType);
            if (authority == null || accountType == null) {
                return null;
            }
            final boolean userVisible =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true);
            final boolean supportsUploading =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_supportsUploading,
                            true);
            final boolean isAlwaysSyncable =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_isAlwaysSyncable,
                            false);
            final boolean allowParallelSyncs =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_allowParallelSyncs,
                            false);
            final String settingsActivity =
                    sa.getString(com.android.internal.R.styleable
                            .SyncAdapter_settingsActivity);
            return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
                    isAlwaysSyncable, allowParallelSyncs, settingsActivity);
        } finally {
            sa.recycle();
        }
    }

    static class MySerializer implements XmlSerializerAndParser {
        public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException {
            out.attribute(null, "authority", item.authority);
            out.attribute(null, "accountType", item.accountType);
        }

        public SyncAdapterType createFromXml(XmlPullParser parser)
                throws IOException, XmlPullParserException {
            final String authority = parser.getAttributeValue(null, "authority");
            final String accountType = parser.getAttributeValue(null, "accountType");
            return SyncAdapterType.newKey(authority, accountType);
        }
    }
}

3.1.2SyncQueue的分析

    private final HashMap mOperationsMap = Maps.newHashMap();

    public SyncQueue(SyncStorageEngine syncStorageEngine, final SyncAdaptersCache syncAdapters) {
        mSyncStorageEngine = syncStorageEngine;
        mSyncAdapters = syncAdapters;
    }

    public void addPendingOperations(int userId) {
        //mSyncStorageEngine取出上次没有完成的同步信息,这些信息由PendingOperation 表示
        for (SyncStorageEngine.PendingOperation op : mSyncStorageEngine.getPendingOperations()) {
            if (op.userId != userId) continue;
            //从mSyncStorageEngine中取出该同步操作的backoff信息
            final Pair backoff = mSyncStorageEngine.getBackoff(
                    op.account, op.userId, op.authority);
            //从SyncAdapterCache中取出该同步操作对应的Service信息
            //如果服务不存在则无需执行之后的流程
            final ServiceInfo syncAdapterInfo = mSyncAdapters.getServiceInfo(
                    SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
            if (syncAdapterInfo == null) { 
                continue;
            }
            //构造一个SyncOperation对象
            SyncOperation syncOperation = new SyncOperation(
                    op.account, op.userId, op.syncSource, op.authority, op.extras, 0 /* delay */,
                    backoff != null ? backoff.first : 0,
                    mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
                    syncAdapterInfo.type.allowParallelSyncs());
            syncOperation.expedited = op.expedited;
            syncOperation.pendingOperation = op;
            add(syncOperation, op);//添加对象
        }
    }

3.1.3StorageSyncEngine

初始化的时候创建了一个目录并在该目录下新增了四个文件
/data/system/sync
/data/system/sync/accounts.xml账户信息
/data/system/sync/pending.bin处于pending状态的同步请求
/data/system/sync/status.bin状态信息
/data/system/sync/stats.bin统计信息

其中accounts.xml文件的内容在添加了davdroid后如下所示











SyncStorageEngine的代码分析

    private SyncStorageEngine(Context context, File dataDir) {
        mContext = context;
        sSyncStorageEngine = this; 
        mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0")); 
        mDefaultMasterSyncAutomatically = mContext.getResources().getBoolean(
               com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically); 
        File systemDir = new File(dataDir, "system");
        File syncDir = new File(systemDir, "sync");
        syncDir.mkdirs();
        mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
        mStatusFile = new AtomicFile(new File(syncDir, "status.bin"));
        mPendingFile = new AtomicFile(new File(syncDir, "pending.bin"));
        mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"));
        //AtomicFile其实内部包括两个文件,其中一个用于数据备份
        readAccountInfoLocked();
        readStatusLocked();
        readPendingOperationsLocked();
        readStatisticsLocked();
        readAndDeleteLegacyAccountInfoLocked();

        writeAccountInfoLocked();
        writeStatusLocked();
        writePendingOperationsLocked();
        writeStatisticsLocked();
    }

    public static SyncStorageEngine newTestInstance(Context context) {
        return new SyncStorageEngine(context, context.getFilesDir());
    }

    public static void init(Context context) {
        if (sSyncStorageEngine != null) {
            return;
        }
        // This call will return the correct directory whether Encrypted File Systems is
        // enabled or not.
        File dataDir = Environment.getSecureDataDirectory();
        sSyncStorageEngine = new SyncStorageEngine(context, dataDir);
    }

3.1.4SyncManager的分析

SyncManger的几位成员的作用

  • SyncAdaptersCache用于管理系统中SyncService的信息,在SyncManager中,SyncService的信息用SyncAdapterType类表示
  • SyncOperation表示一次正在执行或者等待执行的同步操作,而SyncQueue通过mOperationsMap保存系统中存在的SyncOperation
  • SyncStorageEngine保存同步操作的信息,PendingOperation表示保存在本地文件中还没执行完的同步操作,SyncStorageEngine还会对同步操作做统计,如耗电量统计等。
    public SyncManager(Context context, boolean factoryTest) { 
        mContext = context;

        SyncStorageEngine.init(context);
        mSyncStorageEngine = SyncStorageEngine.getSingleton();
        mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
            public void onSyncRequest(Account account, int userId, String authority,
                    Bundle extras) {
                scheduleSync(account, userId, authority, extras, 0, false);
            }
        });

        mSyncAdapters = new SyncAdaptersCache(mContext);
        mSyncQueue = new SyncQueue(mSyncStorageEngine, mSyncAdapters);

        HandlerThread syncThread = new HandlerThread("SyncHandlerThread",
                Process.THREAD_PRIORITY_BACKGROUND);
        syncThread.start();
        mSyncHandler = new SyncHandler(syncThread.getLooper());

        mSyncAdapters.setListener(new RegisteredServicesCacheListener() {
            @Override
            public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
                if (!removed) {
                    scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
                            false /* onlyThoseWithUnkownSyncableState */);
                }
            }
        }, mSyncHandler);
       //创建一个intent,用于和AlarmManagerService交互
        mSyncAlarmIntent = PendingIntent.getBroadcast(
                mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
        //注册CONNECTIVITY_ACTION广播监听,同步操作需要使用网络传数据,所以此处需要监听广播
        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);

        if (!factoryTest) {//监听重启广播
            intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
            context.registerReceiver(mBootCompletedReceiver, intentFilter);
        }

        intentFilter = new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
        context.registerReceiver(mBackgroundDataSettingChanged, intentFilter);
      //监听存储空间广播,保存同步时一些信息存储到设备中
        intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
        context.registerReceiver(mStorageIntentReceiver, intentFilter);

        intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
        intentFilter.setPriority(100);
        context.registerReceiver(mShutdownIntentReceiver, intentFilter);

        intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
        intentFilter.addAction(Intent.ACTION_USER_STARTING);
        intentFilter.addAction(Intent.ACTION_USER_STOPPING);
        mContext.registerReceiverAsUser(
                mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);

        if (!factoryTest) {
            mNotificationMgr = (NotificationManager)
                context.getSystemService(Context.NOTIFICATION_SERVICE);
            context.registerReceiver(new SyncAlarmIntentReceiver(),
                    new IntentFilter(ACTION_SYNC_ALARM));
        } else {
            mNotificationMgr = null;
        }
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);

       //创建wakelock,防止同步过程中掉电
        mHandleAlarmWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                HANDLE_SYNC_ALARM_WAKE_LOCK);
        mHandleAlarmWakeLock.setReferenceCounted(false);

        // This WakeLock is used to ensure that we stay awake while running the sync loop
        // message handler. Normally we will hold a sync adapter wake lock while it is being
        // synced but during the execution of the sync loop it might finish a sync for
        // one sync adapter before starting the sync for the other sync adapter and we
        // don't want the device to go to sleep during that window.
        mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                SYNC_LOOP_WAKE_LOCK);
        mSyncManagerWakeLock.setReferenceCounted(false);
    //监听SyncStorageEngine状态变化
        mSyncStorageEngine.addStatusChangeListener(
                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
            public void onStatusChanged(int which) {
                // force the sync loop to run if the settings change
                sendCheckAlarmsMessage();
            }
        });

        if (!factoryTest) {//监听账户变化
            // Register for account list updates for all users
            mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
                    UserHandle.ALL,
                    new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
                    null, null);
        }

        // Pick a random second in a day to seed all periodic syncs
        mSyncRandomOffsetMillis = mSyncStorageEngine.getSyncRandomOffset() * 1000;
    }


3.2 ConentResolver的requestSync分析

** ConentResolver的requestSync方法用来发起一次同步请求**
如发起邮件同步请求

Account emailAccount = new Account("[email protected]","com.android.yutong");
String emailAuthority = "com.android.email.provider";
Bundle emialBundle = new Bundle();
...
//发起email同步请求
ContentResolver.requestSync(emailAccount,emailAuthority,emialBundle); 

1.ContentResolver的requestSync方法

    public static void requestSync(Account account, String authority, Bundle extras) {
        if (extras == null) {
            throw new IllegalArgumentException("Must specify extras.");
        }
        SyncRequest request =
            new SyncRequest.Builder()
                .setSyncAdapter(account, authority)
                .setExtras(extras)
                .syncOnce()
                .build();
        requestSync(request);
    }

 
    public static void requestSync(SyncRequest request) {
        try {
            getContentService().sync(request);
        } catch(RemoteException e) {
            // Shouldn't happen.
        }
    }

2.ContentService的requestSync方法i调用syncManager.scheduleSync

    public void requestSync(Account account, String authority, Bundle extras) {
        ContentResolver.validateSyncExtrasBundle(extras);
        int userId = UserHandle.getCallingUserId();
     long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                syncManager.scheduleSync(account, userId, authority, extras, 0 /* no delay */,
                        false /* onlyThoseWithUnkownSyncableState */);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    }

3.syncManager.scheduleSync

    /** 
     * @param requestedAccount  要进行同步操作的账户,如果为空,将同步所有账户
     * @param requestedAuthority 要同步的数据项,如果为空,表示全部同步
     * @param extras 同步操作中的参数信息
     * @param delay 延迟多少
     * @param onlyThoseWithUnkownSyncableState决定是否只是同步那些处于unknown状态的数据
     */
    public void scheduleSync(Account requestedAccount, int userId, String requestedAuthority,
            Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
        //判断是否允许后台传输
        final boolean backgroundDataUsageAllowed = !mBootCompleted ||
                getConnectivityManager().getBackgroundDataSetting();

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

        //同步服务中的参数信息
        //SYNC_EXTRAS_EXPEDITED参数表示是否立即执行,如果设置了该参数,则delay不起作用
        Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
        if (expedited) {
            delay = -1; // this means schedule at the front of the queue
        }

        AccountAndUser[] accounts;
        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
        } else {
           ccounts;
            if (accounts.length == 0) { 
                return;
            }
        }
        //SYNC_EXTRAS_UPLOAD表示本次同步不是否上传,从本地同步到服务端是upload
        //反之为downlaod
        final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
        //手动同步,如果是手动同步就忽略SYNC_EXTRAS_IGNORE_BACKOFF和SYNC_EXTRAS_IGNORE_SETTINGS
        final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
        if (manualSync) {
            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
        }
        final boolean 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 {
            // this isn't strictly server, since arbitrary callers can (and do) request
            // a non-forced two-way sync on a specific url
            source = SyncStorageEngine.SOURCE_SERVER;
        }

        for (AccountAndUser account : accounts) {
            //从SyncAdapterCache中取出所有的SyncService信息
            final HashSet syncableAuthorities = new HashSet();
            for (RegisteredServicesCache.ServiceInfo syncAdapter :
                    mSyncAdapters.getAllServices(account.userId)) {
                syncableAuthorities.add(syncAdapter.type.authority);
            }

            //如果指定了本次同步的authority,就从同步服务中找出满足此authority的服务
            if (requestedAuthority != null) {
                final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
                syncableAuthorities.clear();
                if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
            }
            //取出syncable属性值,1为true,-1为unknown
            for (String authority : syncableAuthorities) {
                int isSyncable = mSyncStorageEngine.getIsSyncable(account.account, account.userId,
                        authority);
                if (isSyncable == 0) {
                    continue;
                }
                final RegisteredServicesCache.ServiceInfo syncAdapterInfo;
                syncAdapterInfo = mSyncAdapters.getServiceInfo(
                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
                if (syncAdapterInfo == null) {
                    continue;
                }
                final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
                //如果是unknown切永远是可同步的就设置为true              
                if (isSyncable < 0 && isAlwaysSyncable) {
                    mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);
                    isSyncable = 1;
                }
                //如果只能操作unkonwn但本次不是unknown,就不允许后续的操作
                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
                    continue;
                }
                //如果同步服务不支持上传,但本次服务又需要上传,则不允许后续操作
                if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
                    continue;
                }

                // always allow if the isSyncable state is unknown
                boolean syncAllowed =
                        (isSyncable < 0)
                        || ignoreSettings
                        || (backgroundDataUsageAllowed
                                && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
                                && mSyncStorageEngine.getSyncAutomatically(account.account,
                                        account.userId, authority));
                if (!syncAllowed) { 
                    continue;
                }
                //取出backoff(backoff是指上次没有同步完成的多久之后延迟多少再次同步)
                Pair backoff = mSyncStorageEngine
                        .getBackoff(account.account, account.userId, authority);
                long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
                        account.userId, authority);
                final long backoffTime = backoff != null ? backoff.first : 0;
                if (isSyncable < 0) {
                    Bundle newExtras = new Bundle();
                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
 
                    scheduleSyncOperation(
                            new SyncOperation(account.account, account.userId, source, authority,
                                    newExtras, 0, backoffTime, delayUntil, allowParallelSyncs));
                }
                if (!onlyThoseWithUnkownSyncableState) {
  
                    scheduleSyncOperation(
                            new SyncOperation(account.account, account.userId, source, authority,
                                    extras, delay, backoffTime, delayUntil, allowParallelSyncs));
                }
            }
        }
    }

 

4.scheduleSyncOperation函数
该方法内部将一个SyncOperation对象保存到SyncQueue中,然后发送MESSAGE_CHECK_ALARMS消息

**5. MESSAGE_CHECK_ALARMS的消息处理流程 **

        public void handleMessage(Message msg) {
            long earliestFuturePollTime = Long.MAX_VALUE;
            long nextPendingSyncTime = Long.MAX_VALUE; 
            try {
                waitUntilReadyToRun();
                mDataConnectionIsConnected = readDataConnectionState();
                mSyncManagerWakeLock.acquire(); //防止过程中掉电
                //周期同步操作
                earliestFuturePollTime = scheduleReadyPeriodicSyncs();
                switch (msg.what) {  
                    ......
                    case SyncHandler.MESSAGE_CHECK_ALARMS:
                        //返回一个时间
                        nextPendingSyncTime = maybeStartNextSyncLocked();
                        break;
                }
            } finally {
                manageSyncNotificationLocked();
                manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime);
                mSyncTimeTracker.update();
                mSyncManagerWakeLock.release();
            }
        }

6.maybeStartNextSyncLocked

  • 检查SyncQueue中SyncOperation,判断他们对应的同步服务的状态是否为false,是false就不再继续
  • 检查ConnectivityManagerService以判断同步目标是否使用了网络,如果没有使用网络,就不允许执行同步操作
  • 判断执行时间是否已到,如果未到,则不允许执行
  • 与当前正在执行的同步操作对象对比

7.dispatchSyncOperation
构建一个ActiveSyncContext对象,并将该对象绑定到同步服务上

TU 8-16

  • 通过bindservice启动同步服务,在onServiceConnected函数中得到用于和SyncService交互的接口对象,也就是Binder通信的ISyncAdapter 的Bp端
  • ActiveSyncContext是ISyncContext解扣子Binder通信的Bn端,它调用ISyncAdapter的startSync时,会把自己同步给服务对象,同步服务得到的是ISyncContext的Bp端,当同步服务完成之后就调用ISyncContext的Bp端对象的onFinished函数通知ActiveSyncContext同步操作的结果

8. ActiveSyncContext派发请求

        boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info, int userId) {
          
            Intent intent = 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.getActivityAsUser(
                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,
                    null, new UserHandle(userId)));
            mBound = true;
           bindService启动目标服务
            final boolean bindResult = mContext.bindService(intent, this,
                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                    | Context.BIND_ALLOW_OOM_MANAGEMENT,
                    mSyncOperation.userId);
            if (!bindResult) {
                mBound = false;
            }
            return bindResult;
        }

当目标服务的onBind返回之后,ActiveSyncContext的onServiceConnected将被调用

        public void onServiceConnected(ComponentName name, IBinder service) {
            Message msg = mSyncHandler.obtainMessage();
            msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
            msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
            mSyncHandler.sendMessage(msg);
        }

消息处理函数中调用runBoundToSyncAdapter

                    case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
                        ServiceConnectionData msgData = (ServiceConnectionData)msg.obj; 
                        // check that this isn't an old message
                        if (isSyncStillActive(msgData.activeSyncContext)) {
                            runBoundToSyncAdapter(msgData.activeSyncContext, msgData.syncAdapter);
                        }
                        break;
                    }

runBoundToSyncAdapter会调用目标服务的startSync函数

        private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
              ISyncAdapter syncAdapter) {
            activeSyncContext.mSyncAdapter = syncAdapter;
            final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
            try {
                activeSyncContext.mIsLinkedToDeath = true;
                syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);

                syncAdapter.startSync(activeSyncContext, syncOperation.authority,
                        syncOperation.account, syncOperation.extras);
            } catch (RemoteException remoteExc) {
                
                closeActiveSyncContext(activeSyncContext);
                increaseBackoffSetting(syncOperation);
                scheduleSyncOperation(new SyncOperation(syncOperation));
            } catch (RuntimeException exc) {
                closeActiveSyncContext(activeSyncContext);
               
            }
        }


3.3数据同步管理SyncManager总结

TU 8-18

recyclerview
http://www.jianshu.com/p/2f2996ef2c75
http://www.jianshu.com/p/6c78a5a07db5
http://www.gcssloop.com/customview/matrix-3d-camera
http://www.gcssloop.com/customview/CustomViewIndex
http://blog.devwiki.net/index.php/2016/06/13/RecyclerView-Scroll-Listener.html
http://mp.weixin.qq.com/s?__biz=MzI4MzE2MTQ5Mw==&mid=2649752111&idx=1&sn=414c62ff6c1485c9a7cd90dd3fc8f6e6#rd
http://www.jianshu.com/p/411ab861034f
http://blog.csdn.net/luoyanglizi/article/details/51519686
http://blog.csdn.net/mynameishuangshuai/article/details/51153978
http://blog.csdn.net/huachao1001/article/details/51594004
http://www.jianshu.com/p/c82cebc4e798
http://www.jianshu.com/p/b1ad50633732
http://www.jianshu.com/p/d993ad653293
http://www.jianshu.com/p/87a49f732724
http://mouxuejie.com/blog/2016-03-06/recyclerview-analysis/
http://mijack.github.io/2016/01/07/%E8%AE%A9%20Toolbar%20%E9%9A%8F%E7%9D%80%20RecyclerView%20%E7%9A%84%E6%BB%9A%E5%8A%A8%E8%80%8C%E6%98%BE%E7%A4%BA%E9%9A%90%E8%97%8F/
http://kymjs.com/code/2015/11/26/01/
http://android.jobbole.com/81947/
https://github.com/nuptboyzhb/TreeRecyclerView
http://www.jianshu.com/p/a92955be0a3e
http://blog.csdn.net/u014099894/article/details/51855129
https://github.com/zuiwuyuan/RecycleView_PullToRefresh_LoadMore
http://blog.csdn.net/yanzhenjie1003/article/details/51935982
https://github.com/songhanghang/Smart-HeaderFooter-RecyclerView
http://blog.devwiki.net/index.php/2016/07/24/three-ways-click-recyclerview-item.html
http://www.jianshu.com/p/a3388e716a93
http://kymjs.com/code/2016/07/10/01
https://github.com/oubowu/PinnedSectionItemDecoration/blob/master/README-CN.md
http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html
http://www.jianshu.com/p/12ec590f6c76
https://github.com/dinuscxj/RecyclerItemDecoration
https://segmentfault.com/a/1190000006147436
https://github.com/dinuscxj/PullZoomRecyclerView
http://loshine.me/2016/08/25/a-universal-solution-of-recyclerview-adapter-notify/
http://blog.csdn.net/feiyangbahu1/article/details/52305769
http://www.jianshu.com/p/f592f3715ae2
http://blog.csdn.net/yanzhenjie1003/article/details/52115566
http://www.jianshu.com/p/9bfed6e127cc
https://github.com/CymChad/CymChad.github.io
https://github.com/lufficc/LightAdapter
https://github.com/markzhai/DataBindingAdapter
http://www.jianshu.com/p/66c065874848
http://blog.csdn.net/zxt0601/article/details/52420706
http://blog.csdn.net/qifengdeqingchen/article/details/52388467
https://github.com/kHRYSTAL/CircleRecyclerView
http://hanhailong.com/2015/12/28/Android%E8%BF%9B%E9%98%B6%E4%B9%8BProGuard%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7%86/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
http://blog.csdn.net/lmj623565791/article/details/46858663
https://github.com/bboyfeiyu/android-tech-frontier/blob/master/issue-18/%E6%8B%96%E6%8B%BDRecyclerView.md
http://androidone.io/info_10265.html
https://github.com/cymcsg/UltimateRecyclerView
http://www.itlanbao.com/code/20150812/10050/100317.html
http://www.itlanbao.com/code/20150812/10050/100316.html
http://www.itlanbao.com/code/20150812/10050/100322.html
http://www.itlanbao.com/code/20150812/10050/100323.html
http://www.itlanbao.com/code/20151111/10000/100639.html
http://www.jianshu.com/p/a6f158d1a9c9

你可能感兴趣的:(ContentService:第二部分数据同步)