同步适配器是一个由android平台处理的service,该service通过账户实现与服务器的身份验证,使用ContentProvider同步数据。实现同步适配器后,应用程序可以自动与服务器一起注册到设备中。同步适配器每次只运行一个,这样就可以避免网络阻塞。
实现同步适配器需要以下几步:
1. 清单文件中声明该同步适配器
<service android:name= ".service.TodoSyncService" >
<intent-filter >
<action android:name ="android.content.SyncAdapter" />
</intent-filter >
<meta-data
android:name= "android.content.SyncAdapter"
android:resource= "@xml/todo_sync_adapter" />
</service>
2. service引入的资源文件
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.manning.androidhacks.hack023.provider.TodoContentProvider"
android:accountType="com.manning.androidhacks.hack023" />
其中用到了内容提供者的authority和accountType,一定要一致
3. 实现继承自AbstractThreadSyncAdapter的类,源码如下
public class TodoSyncAdapter extends AbstractThreadedSyncAdapter {
private static final String TAG = TodoSyncAdapter.class.getCanonicalName();
private final ContentResolver mContentResolver;
private AccountManager mAccountManager;
private final static TodoDAO mTodoDAO = TodoDAO.getInstance();
public TodoSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContentResolver = context.getContentResolver();
mAccountManager = AccountManager. get(context);
}
// 这个方法是在后台线程中执行的,与服务器同步的逻辑就放在该方法中。
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
String authtoken = null;
try {
authtoken = mAccountManager.blockingGetAuthToken(account,
AuthenticatorActivity. PARAM_AUTHTOKEN_TYPE, true );
// 第一步,从服务器获取数据
List<Todo> data = fetchData();
// 第二步,从本地删除服务器端已经删除的条目
syncRemoteDeleted(data);
// 第三步,把服务器数据同步到本地
syncFromServerToLocalStorage(data);
// 第四步,把本地同步到服务器
syncDirtyToServer( mTodoDAO.getDirtyList( mContentResolver));
} catch (Exception e) {
handleException(authtoken, e, syncResult);
}
}
// 处理异常
private void handleException(String authtoken, Exception e,
SyncResult syncResult) {
if (e instanceof AuthenticatorException) {
syncResult. stats. numParseExceptions++;
Log. e(TAG, "AuthenticatorException" , e);
} else if (e instanceof OperationCanceledException) {
Log. e(TAG, "OperationCanceledExcepion" , e);
} else if (e instanceof IOException) {
Log. e(TAG, "IOException" , e);
syncResult. stats. numIoExceptions++;
} else if (e instanceof AuthenticationException) {
mAccountManager.invalidateAuthToken(
AuthenticatorActivity. PARAM_ACCOUNT_TYPE, authtoken);
// The numAuthExceptions require user intervention and are
// considered hard errors.
// We automatically get a new hash, so let's make SyncManager retry
// automatically.
syncResult. stats. numIoExceptions++;
Log. e(TAG, "AuthenticationException" , e);
} else if (e instanceof ParseException) {
syncResult. stats. numParseExceptions++;
Log. e(TAG, "ParseException" , e);
} else if (e instanceof JsonParseException) {
syncResult. stats. numParseExceptions++;
Log. e(TAG, "JSONException" , e);
} else if (e instanceof AndroidHacksException) {
Log. e(TAG, "AndroidHacksException" , e);
}
}
}
4. 最后一步是实现上述的service
public
class
TodoSyncService
extends
Service {
private
static
final
Object
sSyncAdapterLock
=
new
Object();
private
static
TodoSyncAdapter
sSyncAdapter
=
null
;
@Override
public
void
onCreate() {
synchronized
(
sSyncAdapterLock
) {
if
(
sSyncAdapter
==
null
) {
sSyncAdapter
=
new
TodoSyncAdapter(getApplicationContext(),
true
);
}
}
}
@Override
public
IBinder onBind(Intent intent) {
return
sSyncAdapter
.getSyncAdapterBinder();
}
}