2

I have the following scenario.

I use a SyncAdapter in my app to download data from a server.

When the user opens the app I call requestSync() to make sure the latest data are available.

When the user requests it I call again requestSync() passing a bundle of the specific datum I want to download.

The problem is the following:

I can use a SyncStatusObserver to get notified about the status of the download, but that will not tell me which sync is completed:

For example:

  • at app start I start a "Total" sync,

  • then the user requests a refresh on a specific datum, hence I launch a "Specific sync of datum foo",

  • the SyncStatusObserver will tell me that a sync is pending/active, but won't tell me if that is the "Total" sync or the "Specific sync of datum foo"

How can i do it?

Is intent broadcast the only way?

user229044
  • 232,980
  • 40
  • 330
  • 338
Lisa Anne
  • 4,482
  • 17
  • 83
  • 157

1 Answers1

1

SyncStatusObserver won't tell you that, but there are multiple ways to accomplish that and it depends a lot on your architecture.

Here's one that works for us:

We're planning to let our SyncAdapter return another IBinder and return that one when binding our SyncService with a specific action. This IBinder object will provide information about the current status of the sync adapter. This works because there's only one instance of a sync service and our sync service holds exactly one instance of the sync adapter.

Here's a quick example:

At present the onBind(Intent) method of our sync service looks like this:

@Override
public IBinder onBind(Intent intent)
{
    return sSyncAdapter.getSyncAdapterBinder();
}

Where sSyncAdapter is a static instance of our sync adapter.

We're planing to change that to something like this:

public final static ACTION_SYNC_INFO = "com.example.SYNC_INFO";

@Override
public IBinder onBind(Intent intent)
{
    if (ACTION_SYNC_INFO.equals(intent.getAction())
    {
        // sync info binder has been requested
        return sSyncAdapter.getSyncInfoBinder();
    }
    // otherwise return the sync adapter binder
    return sSyncAdapter.getSyncAdapterBinder();
}

In our activity we bind our sync service and set the action SyncService.ACTION_SYNC_INFO. That tells the sync service to return the sync info binder instead of the sync adapter binder.

The binder will have an interface that could look like this:

public interface SyncInfoBinder extends IBinder
{
    public boolean isTotalSync();
}

Of course, the sync adapter still needs to implement this method which (in your case) could look like this:

private abstract class AbstractSyncInfoBinder extends Binder implements SyncInfoBinder
{
}

private final IBinder mSyncInfoBinder = new AbstractSyncInfoBinder()
{
     @Override
     public boolean isTotalSync()
     {
          // return some field that was set by your onPerformSync method
          return mCurrentSyncIsTotalSync;
     }
}

public IBinder getSyncInfoBinder()
{
    return mSyncInfoBinder
}

Of course that only works this easily if your sync adapter is set to be single threaded. For multi-threaded sync adapters you have to take additional steps to make sure you get the status of all ongoing syncs.

In any case this is a nice way of getting live results from the sync adapter to present them in your UI.

Marten
  • 3,802
  • 1
  • 17
  • 26
  • Hi Marten, that indeed is a very nice solution, thanks +1! I am surprised that with all the efforts Google took in implementing the ContentProvider/SyncAdapter architecture, it did not provide an API to do just what I need, it is a very common scenario! – Lisa Anne Feb 02 '16 at 09:25
  • I think the Android architects did a brilliant job when designing the Service/Activity/Broadcast intent stuff and I'm often surprised that I can cover so many use cases, like the one above. The approach above is actually much better for this purpose than a pure ContentProvider based solution could possibly be, because it gives you much more control. It actually allows you to communicate both ways with the sync adapter thread during a sync. – Marten Feb 02 '16 at 09:48
  • Hello, can you please tell me how do you fetch the "isTotalSync" result in your activity ? thank you very much – Rada Bogdan Feb 03 '17 at 15:57
  • @RadaBogdan a comment is not long enough to give an exhaustive answer, so the short answer is: you bind the service as shown in https://developer.android.com/guide/components/bound-services.html#Binder and call `isTotalSync()` on the `IBinder` that you get when the service is bound. You'll have to cast the Binder to `SyncInfoBinder` to make this work. – Marten Feb 05 '17 at 13:08
  • Thank You very much – Rada Bogdan Feb 06 '17 at 21:03