3

I've been developing for Android for some time now and currently working with syncing with my server.
Quick introduction: I've read about Sync Adapter and do know its role but I just want to know if it's my best option.

In my app user can click on a button to notify something is important to him. On click I'd like to update the server to keep the data, as well as notify his relatives. My problem comes as follows: The user can click that said button several times switching it on and off so in that case I don't want to open communication with the server each time the user clicks a button, it might not even change state from its previous state.

So my question is: Is sync adapter the right thing for me or should I build my own class to talk to the server that will check that, as well as receive urgent\non-urgent like Volley's. If someone could clarify the exact work of Sync Adapter I'd really appreciate it (Does it do what I stated?)

If something isn't clear i'd be happy to clarify. Thanks in advance.

user2558461
  • 281
  • 1
  • 6
  • 21

4 Answers4

1

Android sync framework should be pretty good for your use. If you mark a sync as needed, the system will not launch it right now, but delay it for a small time. This way, if the user switch back the button, you'll be able to notice that no value has changed. Sidenote: if you use a ContentProvider, it notifies the SyncAdapter automagically when data changes. You can also trigger a sync manually if needed.

What the sync framework do is just calling a method (onPerformSync). You're free to implement it as you want. You can skip a sync if you think the last one was too close, or find if data has really changed, or it's back to original value (you can for example keep the "last synced" value in your database, then you can compare it to the current value in your onPerformSync method. If it's the same, no change).

Bonus: you'll save battery power, as the sync framework run multiple syncs in sequence as much as possible, your users will be able to manage their accounts in a centralized place (Android settings), disable sync system-wide (think about Sony's stamina-mode, setting every SyncAdapter in pause while active).

Marc Plano-Lesay
  • 6,808
  • 10
  • 44
  • 75
  • Is there a way to cancel the ability to switch the sync off via the Settings? I'm worried it will mess up my logic – user2558461 Oct 21 '13 at 17:18
  • Yes: see the attribute `android:userVisible` (http://developer.android.com/reference/android/content/AbstractThreadedSyncAdapter.html) – Marc Plano-Lesay Oct 22 '13 at 07:55
  • Could you maybe provide some examples? before I hand you the bounty? – user2558461 Oct 26 '13 at 21:41
  • Udinic wrote a pretty complete introduction here: http://udinic.wordpress.com/2013/07/24/write-your-own-android-sync-adapter/ with a sample here: https://github.com/Udinic/SyncAdapter – Marc Plano-Lesay Oct 27 '13 at 12:58
0

You could also take another approach, pushing from your server to the device, your app does not have to ask from time to time for updates, instead its the server that should tell "hey, i've got something for you".

Have a look at Google Cloud Messaging. On the other hand, if you prefer the approach that the user should specifically ask for his updates then you don't really need to bother if sync adapters - ofcourse, this depends on your app's requirements.

Still, I'd recommend you have a look at GCM, it's cleaner and more elegant for the server to notify then to keep asking.

Marius M
  • 496
  • 9
  • 16
  • I'm using GCM for notification on the other way around. I'm currently asking about updating the server I had changed something. not updates – user2558461 Oct 22 '13 at 15:39
  • Ohh, okey, I have misunderstood; This should be pretty straight forward then, just send a notification to the server that something has happened right after that specific action has completed; is the app suppose to handle off-line situations as well? or do you have to persist some data while off-line? – Marius M Oct 22 '13 at 15:50
  • Please read the question, I don't want to open http socket each time the user had made something, because like I described, he may have just clicked on/off the same button multiple times that the data may not even change. – user2558461 Oct 22 '13 at 15:56
  • When the user takes an action persist that action locally, this way you cover the offline situation as well. You should not open a socket or do any http requests unless there is something stored locally, ofcourse - after you've sent your data to the server, you clear it locally. – Marius M Oct 22 '13 at 15:59
  • If you use a SyncAdapter, storing data in a ContentProvider bound to the SyncAdapter will automatically trigger a pending sync. Depending on the last sync time, it will be launched immediately or wait for a moment. Two automatic syncs are never triggered more than once a minute. – Marc Plano-Lesay Oct 25 '13 at 11:32
0

Run a sync adapter when data changes on the device. This option allows you to send modified data from the device to a server, and is especially useful if you need to ensure that the server always has the latest device data. This option is straightforward to implement if you actually store data in your content provider. If you're using a stub content provider, detecting data changes may be more difficult.

Run the sync adapter in response to a user action. However, to provide the best user experience you should rely primarily on one of the more automated options.

You can run your sync adapter periodically by setting a period of time to wait between runs, or by running it at certain times of the day, or both. Running your sync adapter periodically allows you to roughly match the update interval of your server.

akshay
  • 5,811
  • 5
  • 39
  • 58
0

Run the Sync Adapter When Content Provider Data Changes

public class MainActivity extends FragmentActivity {
...
// Constants
// Content provider scheme
public static final String SCHEME = "content://";
// Content provider authority
public static final String AUTHORITY = "com.example.android.datasync.provider";
// Path for the content provider table
public static final String TABLE_PATH = "data_table";
// Account
public static final String ACCOUNT = "default_account";
// Global variables
// A content URI for the content provider's data table
Uri mUri;
// A content resolver for accessing the provider
ContentResolver mResolver;
...
public class TableObserver extends ContentObserver {
    /*
     * Define a method that's called when data in the
     * observed content provider changes.
     * This method signature is provided for compatibility with
     * older platforms.
     */
    @Override
    public void onChange(boolean selfChange) {
        /*
         * Invoke the method signature available as of
         * Android platform version 4.1, with a null URI.
         */
        onChange(selfChange, null);
    }
    /*
     * Define a method that's called when data in the
     * observed content provider changes.
     */
    @Override
    public void onChange(boolean selfChange, Uri changeUri) {
        /*
         * Ask the framework to run your sync adapter.
         * To maintain backward compatibility, assume that
         * changeUri is null.
        ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
    }
    ...
}
...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    // Get the content resolver object for your app
    mResolver = getContentResolver();
    // Construct a URI that points to the content provider data table
    mUri = new Uri.Builder()
              .scheme(SCHEME)
              .authority(AUTHORITY)
              .path(TABLE_PATH)
              .build();
    /*
     * Create a content observer object.
     * Its code does not mutate the provider, so set
     * selfChange to "false"
     */
    TableObserver observer = new TableObserver(false);
    /*
     * Register the observer for the data table. The table's path
     * and any of its subpaths trigger the observer.
     */
    mResolver.registerContentObserver(mUri, true, observer);
    ...
}
...

}

akshay
  • 5,811
  • 5
  • 39
  • 58
  • Could you explain some about the finals you declared? – user2558461 Oct 27 '13 at 17:20
  • Those variable are used for creating uri. new Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .path(TABLE_PATH) .build(); – akshay Oct 28 '13 at 09:38
  • Note that if you bind your SyncAdapter to your ContentProvider (given you want to observe only one provider), you don't need all this. You can bind them, in the `sync-adapter` XML, with the `android:contentAuthority` attribute. A pending sync will be triggered every time your ContentProvider notifies its observers. – Marc Plano-Lesay Oct 28 '13 at 15:10