android多个请求同步,Android 同步机制解析

场景解析

信息同步场景很多,如电子邮件的收取、笔记应用的云备份、天气应用的及时同步。核心诉求就是两个:

把设备数据同步到服务器。

把服务器数据同步设备。

解决方案

最简单的解决方案,就是终端直接发起网络请求。但在Android设备上会存在 App被杀死,无法及时后台同步,导致再次启动app时,数据没有更新的情形。

有问题就需要解决方案,Android系统默认提供了一套方案——SyncAdapters,其特点如下:

将所有的数据传输都放到同一个地方,以便操作系统智能地安排数据传输,优化电池性能。

可以智能安排数据传输,如检查网络连接、下载失败后重试等。可以根据不同条件自动发起数据传输,如服务器数据变更、定时同步等。

使用SyncAdapter可以加快应用的加载时间、实现离线功能,可以在数据及时同步和减少网络调用以节约电池电量之间达到一种平衡局面。

如何配置SyncAdapter

首先,我们要了解Android系统是如何理解同步这件事的。对系统而言,同步的意思是某个账户 同步 某些数据 。

所以,SyncAdapter需要上层应用提供三类信息:账户、数据、同步动作。具体代码如下:

1. 账户组件Authenticator

分为三个部分:账户认证、配置文件、账户认证服务。最后将账户认证服务注册到Anroid系统中即可。

1.1 账户认证器 StubAuthenticator

系统设置→账户→添加账户 的时候会调用其 addAccount 方法。下面是一个不需要账户认证的实现。

public class StubAuthenticator extends AbstractAccountAuthenticator {

public StubAuthenticator(Context context) {

super(context);

}

@Override

public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,

String s) {

throw new UnsupportedOperationException();

}

@Override

public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse, String s,

String s2, String[] strings, Bundle bundle) throws NetworkErrorException {

return null;

}

@Override

public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,

Account account, Bundle bundle) throws NetworkErrorException {

return null;

}

@Override

public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,

Account account, String s, Bundle bundle) throws NetworkErrorException {

throw new UnsupportedOperationException();

}

@Override

public String getAuthTokenLabel(String s) {

throw new UnsupportedOperationException();

}

@Override

public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,

Account account, String s, Bundle bundle) throws NetworkErrorException {

throw new UnsupportedOperationException();

}

@Override

public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,

Account account, String[] strings) throws NetworkErrorException {

throw new UnsupportedOperationException();

}

}

1.2 配置文件为 authenticator.xml

放在 res/xml 目录下,一般内容如下:

android:accountType="com.eutechpro.syncadapterexample"

android:icon="@drawable/ic_launcher"

android:smallIcon="@drawable/ic_launcher"

android:label="@string/app_name" />

android:accountType:账户类型,系统唯一,一般采用系统包名为前缀

android:icon:图标,显示在“设置”应用的“账号”一项中。

android:smallIcon:小图标,根据屏幕尺寸可能在设置中代替icon属性。

android:label:标识账户类型,一般为应用名,显示在“设置”应用的“账号”一项中。

1.3 账户认证服务 StubAuthenticatorService

沟通 SyncAdapter framework 和 Authenticator,提供一个远程程序调用RPC 的 IBinder

public class StubAuthenticatorService extends Service {

private StubAuthenticator authenticator;

@Override

public void onCreate() {

authenticator = new StubAuthenticator(this);

}

/*

* When the system binds to this Service to make the RPC call

* return the authenticator’s IBinder.

*/

@Override

public IBinder onBind(Intent intent) {

return authenticator.getIBinder();

}

}

1.4 将Service注册到系统中

android:name="android.accounts.AccountAuthenticator"

android:resource="@xml/authenticator" />

2. 数据组件ContentProvider。

下面是一个空Provider的实现。

public class StubContentProvider extends ContentProvider {

@Override

public boolean onCreate() {

return true;

}

@Override

public Cursor query(Uri uri, String[] columns, String selection, String[] selectionArgs, String sortOrder) {

return null;

}

@Override

public String getType(Uri uri) {

return null;

}

@Nullable

@Override

public Uri insert(Uri uri, ContentValues contentValues) {

return null;

}

@Override

public int delete(Uri uri, String s, String[] strings) {

return 0;

}

@Override

public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {

return 0;

}

}

同样需要将其注册到系统中:

android:name="ch.teleboy.sync_app_settings.StubContentProvider"

android:authorities="com.eutechpro.syncadapterexample.provider"

android:exported="false"

android:syncable="true">

3. 同步组件SyncAdapter。

氛围三个部分:同步器、配置文件、同步服务。最后将同步服务注册到系统即可。

3.1 同步器SyncAdapter

最终同步相关代码放在onPerformSync方法里面。

public class SyncAdapter extends AbstractThreadedSyncAdapter {

public SyncAdapter(Context context, boolean autoInitialize) {

super(context, autoInitialize);

}

@Override

public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient contentProviderClient, SyncResult syncResult) {

System.out.println("******* onPerformSync *******");

// System.out.println("*******" + syncResult.syncAlreadyInProgress+" *******");

System.out.println("*****************************");

}

}

3.2 配置文件

android:contentAuthority="com.eutechpro.syncadapterexample.provider"

android:accountType="com.eutechpro.syncadapterexample"

android:allowParallelSyncs="false"

android:isAlwaysSyncable="true"

android:supportsUploading="false"

android:userVisible="true" />

android:contentAuthority 指定要同步的ContentProvider在其AndroidManifest.xml文件中有个android:authorities属性。

android:accountType 表示进行同步的账号的类型。

android:allowParallelSyncs 是否支持多账号同时同步

android:isAlwaysSyncable 设置所有账号的isSyncable为true

android:supportsUploading 设置是否必须notifyChange通知才能同步

android:syncAdapterSettingsAction 指定一个可以设置同步的activity的Action。

android:userVisible 设置是否在“设置”中显示

3.3 同步服务

public class SyncAdapterService extends Service {

private static SyncAdapter syncAdapter = null;

// Object to use as a thread-safe lock

private static final Object syncAdapterLock = new Object();

@Override

public void onCreate() {

super.onCreate();

/*

* Create the sync adapter as a singleton.

* Set the sync adapter as syncable

* Disallow parallel syncs

*/

synchronized (syncAdapterLock) {

if (syncAdapter == null) {

syncAdapter = new SyncAdapter(getApplicationContext(), true);

}

}

}

/**

* Return an object that allows the system to invoke the sync adapter.

*/

@Override

public IBinder onBind(Intent intent) {

/*

* Get the object that allows external processes

* to call onPerformSync(). The object is created

* in the base class code when the SyncAdapter

* constructors call super()

*/

return syncAdapter.getSyncAdapterBinder();

}

}

如何使用SyncAdapter

建立账户init。

主动调用forceRefresh 或者等待系统择机调用。

参考代码如下:

public static void init(Context context) {

newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);

AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);

if (accountManager.addAccountExplicitly(newAccount, null, null)) {

System.out.println("添加 acc");

} else {

System.out.println("已经添加过啦");

}

ContentResolver.setSyncAutomatically(newAccount, AUTHORITY, true);

}

public static void forceRefresh() {

Bundle bundle = new Bundle();

bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);

ContentResolver.requestSync(newAccount, AUTHORITY, bundle);

}

注意:

xml中的各处的 android:accountType、android:contentAuthority 必须保持一直。

参考:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值