I am currently trying to synchronize some data with a server using a background service. Using the following sites as guides:
I also scoured StackOverflow and have tried the following solutions:
I have tried other solutions on StackOverflow as well but the solutions are essentially encapsulated by those listed above. I am wondering if there is something missing where I need to start this service in my code.
SyncService.java:
public class SyncService extends Service {
private static SyncAdapter syncAdapter = null;
private static final Object syncAdapterLock = new Object();
@Override
public void onCreate() {
super.onCreate();
Log.d("SyncService", "[DEBUG] SyncService created...");
synchronized (syncAdapterLock) {
if (syncAdapter == null) {
syncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("SyncService", "[DEBUG] onBind(...) run for SyncAdapter...");
return syncAdapter.getSyncAdapterBinder();
}
}
SyncAdapter.java:
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private ContentResolver resolver;
private AccountManager am;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
resolver = context.getContentResolver();
am = AccountManager.get(context);
}
// Maintains compatibility with Android >= 3.0 platform versions
public SyncAdapter(Context context , boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
resolver = context.getContentResolver();
am = AccountManager.get(context);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d("SyncAdapter", "[DEBUG] onPerformSync for account[" + account.name + "] called. Syncing....");
// Connect to server
// Download and upload data
// Handle data conflicts and determining if data is current
// Clean up
}
}
Observer:
public class AlarmObserver extends ContentObserver {
Account account;
public AlarmObserver(Handler handler, Account account) {
super(handler);
this.account = account;
}
@Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
@Override
public void onChange(boolean selfChange, Uri changeUri) {
Log.d("AlarmObserver", "[DEBUG] Change to content detected. Account: " + account.name + " Uri: " + changeUri.toString() + " Authority: " + AlarmContract.AUTHORITY);
ContentResolver.requestSync(account, AlarmContract.AUTHORITY, new Bundle());
}
}
syncadapter.xml:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="livotto.smarthomeapi.AlarmProvider"
android:accountType="@string/default_account_type"
android:userVisible="true"
android:supportsUploading="true"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true" />
Activity where I am using the resolver:
AccountManager am = AccountManager.get(this);
Account[] accounts = am.getAccounts();
if (accounts.length > 1) {
// Dialog should appear asking which account to use
}
account = accounts[0]; // for now we take the first account
resolver = getContentResolver();
observer = new AlarmObserver(new Handler(), account);
resolver.registerContentObserver(AlarmContract.CONTENT_URI, true, observer);
I have solved the problem I was getting. There are some flags that will control how the sync adapter runs. These are:
ContentResolver.SYNC_EXTRAS_MANUAL
ContentResolver.SYNC_EXTRAS_EXPEDITED
You can set this with the following:
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(ACCOUNT, AUTHORITY, bundle);
For more information about what these flags do: