SyncAdapter 无限循环
Infinite loop of SyncAdapter
昨天我在 Genymotion 的一些虚拟设备上测试了我的应用程序,我有时意识到,应用程序向某些设备上的服务器发送无限同步请求(所有这些都是 API<21)。有什么问题吗?
让我们提供一些有关该项目的信息:
我在我的项目中使用了 SyncAdapter 和 Room Persistence。
当我阅读 android 文档时,我必须使用 ContentProvider 从 SyncAdapter 访问数据库。但是我将 ContentProvider 留空并直接从 SyncAdapter 连接到 Room。部分项目代码可以帮助大家想象操作:
同步适配器class:
public class SyncAdapter extends AbstractThreadedSyncAdapter {
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
if (!AppCheckUtils.appInForeground(getContext())) {
SyncDataWithServer.sendRequest(getContext());
}
}
}
内容提供者class:
public class DataContentProvider extends ContentProvider {
@Override public boolean onCreate() {
return true;
}
@Nullable @Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable @Override public String getType(@NonNull Uri uri) {
return null;
}
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
}
AndroidManifest.xml:
...
<provider
android:name=".contentProvider.DataContentProvider"
android:authorities="@string/syncContentProvider"
android:exported="false"
android:syncable="true"/>
...
SyncAdapter.xml:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/console_account"
android:allowParallelSyncs="false"
android:contentAuthority="@string/syncContentProvider"
android:isAlwaysSyncable="true"
android:supportsUploading="false"
android:userVisible="false"/>
SyncDataWithServer class:
public class SyncDataWithServer {
private static RESTConnector<SyncResult> messagesREST;
private static final Object lockObject = new Object();
public static void sendRequest(Context context) {
synchronized (lockObject) {
if (messagesREST == null)
messagesREST =
new RESTConnector<>(SendTokenCondition.USERTOKEN__TEMPCODE, false, (ToastErrMsg) null,
true, 0);
}
if (BasicAuth.hasTokenOrTempCode()) {
if (SerCons.BASE_ST.contains("twitch.tv")) {
return;
}
SettingDataDaoHnd
.getSyncSettings(context, syncSettings -> sendRequest(context, syncSettings));
}
}
private static void sendRequest(Context context, SyncSettingsFromDB syncSettings) {
...
}
}
我发现了问题。
当我调用 accountManager.addAccount(..) 或 accountManager.removeAccount(..) 或 accountManager.setPassword 时,它会导致调用 syncAdapter.onPerformSync(..) 然后向服务器发送请求,.. . .它会导致无限循环。
我在调用 ContentResolver
时通过向 Bundle 添加额外内容解决了这个问题
Bundle bundle = new Bundle();
bundle.putBoolean(IntentCons.SYNC_ADAPTER_DO_SYNC, true);
ContentResolver.addPeriodicSync(account, authority, bundle, syncPeriod);
然后在 onPerformSync 中:
@Override public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
boolean doSync = extras.containsKey(IntentCons.SYNC_ADAPTER_DO_SYNC) && extras.getBoolean(IntentCons.SYNC_ADAPTER_DO_SYNC);
if (doSync) {
SyncDataWithServer.sendRequest(getContext());
}
}
昨天我在 Genymotion 的一些虚拟设备上测试了我的应用程序,我有时意识到,应用程序向某些设备上的服务器发送无限同步请求(所有这些都是 API<21)。有什么问题吗?
让我们提供一些有关该项目的信息: 我在我的项目中使用了 SyncAdapter 和 Room Persistence。 当我阅读 android 文档时,我必须使用 ContentProvider 从 SyncAdapter 访问数据库。但是我将 ContentProvider 留空并直接从 SyncAdapter 连接到 Room。部分项目代码可以帮助大家想象操作:
同步适配器class:
public class SyncAdapter extends AbstractThreadedSyncAdapter {
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
if (!AppCheckUtils.appInForeground(getContext())) {
SyncDataWithServer.sendRequest(getContext());
}
}
}
内容提供者class:
public class DataContentProvider extends ContentProvider {
@Override public boolean onCreate() {
return true;
}
@Nullable @Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable @Override public String getType(@NonNull Uri uri) {
return null;
}
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
}
AndroidManifest.xml:
...
<provider
android:name=".contentProvider.DataContentProvider"
android:authorities="@string/syncContentProvider"
android:exported="false"
android:syncable="true"/>
...
SyncAdapter.xml:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/console_account"
android:allowParallelSyncs="false"
android:contentAuthority="@string/syncContentProvider"
android:isAlwaysSyncable="true"
android:supportsUploading="false"
android:userVisible="false"/>
SyncDataWithServer class:
public class SyncDataWithServer {
private static RESTConnector<SyncResult> messagesREST;
private static final Object lockObject = new Object();
public static void sendRequest(Context context) {
synchronized (lockObject) {
if (messagesREST == null)
messagesREST =
new RESTConnector<>(SendTokenCondition.USERTOKEN__TEMPCODE, false, (ToastErrMsg) null,
true, 0);
}
if (BasicAuth.hasTokenOrTempCode()) {
if (SerCons.BASE_ST.contains("twitch.tv")) {
return;
}
SettingDataDaoHnd
.getSyncSettings(context, syncSettings -> sendRequest(context, syncSettings));
}
}
private static void sendRequest(Context context, SyncSettingsFromDB syncSettings) {
...
}
}
我发现了问题。 当我调用 accountManager.addAccount(..) 或 accountManager.removeAccount(..) 或 accountManager.setPassword 时,它会导致调用 syncAdapter.onPerformSync(..) 然后向服务器发送请求,.. . .它会导致无限循环。 我在调用 ContentResolver
时通过向 Bundle 添加额外内容解决了这个问题Bundle bundle = new Bundle();
bundle.putBoolean(IntentCons.SYNC_ADAPTER_DO_SYNC, true);
ContentResolver.addPeriodicSync(account, authority, bundle, syncPeriod);
然后在 onPerformSync 中:
@Override public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
boolean doSync = extras.containsKey(IntentCons.SYNC_ADAPTER_DO_SYNC) && extras.getBoolean(IntentCons.SYNC_ADAPTER_DO_SYNC);
if (doSync) {
SyncDataWithServer.sendRequest(getContext());
}
}