I wrote SyncAdapter with Content Provider. It works fine, when I call sync manually:
ContentResolver.requestSync(AccountHelper.getAccount(),
SvoDataContract.AUTHORITY,
new Bundle());
But SyncAdapter doesn't update DB when called by the system (when we turn on wi-fi for example). It seems ContentProvider applies changes to cache or another DB, because I use logs before and after update and I can see that read operation returns exactly my values, that I used for updating. But when I open my SQLite db file, there is no changes. Very strange behavior.
My SyncAdapter:
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private static final String TAG = "SVOSyncAdapter";
private static final int REQUEST_TIMEOUT = 30000;
private static final int HTTP_NOT_FOUND = 404;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
DebugLog.i(TAG, context.getApplicationInfo().toString());
}
@Override
public void onPerformSync(Account account,
Bundle extras,
String authority,
ContentProviderClient provider,
SyncResult syncResult) {
syncJourney(provider, getContext());
}
private void syncJourney(final ContentProviderClient provider, final Context context) {
List<Journey> journeyList = JourneyDAO.read(context, true);
syncEntities(journeyList, new IOnSyncCallback<Journey>() {
@Override
public void onSuccess(Journey entity, Journey modifiedEntity) {
if (entity.getState() == SqlContract.BackendSynchronized.State.CREATED) {
entity.setId(modifiedEntity.getId());
}
entity.setNeedSync(false);
if (entity.getId() != null) {
DebugLog.i(TAG, String.format("Updating journey: %s", entity.getId().toString()));
}
String where = String.format("%s=?", BaseColumns._ID);
String[] args = {String.valueOf(entity.getLocalId())};
try {
provider.update(SvoDataContract.Journey.CONTENT_URI,
JourneyDAO.createContentValues(entity),
where,
args);
Cursor cursor = provider.query(SvoDataContract.Journey.CONTENT_URI, null, where, args, null);
if (cursor.moveToFirst()) {
DebugLog.i(TAG,
String.format("After update: %d",
CursorHelper.getInt(cursor,
SqlContract.Journey.COLUMN_SERVER_ID)));
} // It looks like we wrote data to DB successfully
cursor.close();
} catch (RemoteException re) {
DebugLog.i(TAG, "Remote exception");
}
}
@Override
public void onFail(Journey entity, int networkError) {
if (networkError == HTTP_NOT_FOUND) {
DebugLog.i(TAG, "fail");
entity.setNeedSync(false);
String where = String.format("%s=?", BaseColumns._ID);
String[] args = {String.valueOf(entity.getLocalId())};
try {
provider.update(SvoDataContract.Journey.CONTENT_URI,
JourneyDAO.createContentValues(entity),
where,
args);
} catch (RemoteException re) {
DebugLog.i(TAG, "Remote exception");
}
}
}
});
}
private <T extends ISyncEntity> void syncEntities(final List<T> entities, final IOnSyncCallback<T> syncCallback) {
// some work with Backend
}
private interface IOnSyncCallback<T> {
void onSuccess(T entity, T modifiedEntity);
void onFail(T entity, int networkError);
}
}
My manifest:
<provider
android:name=".provider.SvoContentProvider"
android:authorities="ru.agencyprime.svo.provider"
android:enabled="true"
android:syncable="true"
android:multiprocess="true"
android:exported="true" >
</provider>
<service
android:name=".sync.account.AuthenticatorService"
android:exported="false">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<service
android:name=".sync.SyncService"
android:exported="false"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter" />
</service>
SyncAdapter registration:
public class AccountHelper {
public static final String ACCOUNT_TYPE = "ru.agencyprime.svo.account";
private static Account account;
private AccountHelper() {
}
public static void register(Context context) {
final AccountManager am = AccountManager.get(context);
if (account == null) {
account = new Account(context.getString(R.string.sync_my_journeys), ACCOUNT_TYPE);
}
if (am.addAccountExplicitly(account, context.getPackageName(), new Bundle())) {
ContentResolver.setSyncAutomatically(account, SvoDataContract.AUTHORITY, true);
}
}
public static Account getAccount() {
return account;
}
}
What could be wrong? I am confused that it works fine with manual synchronisation.
Aucun commentaire:
Enregistrer un commentaire