Android SyncAdapter: how to get notified of specif

2019-07-10 05:36发布

问题:

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?

回答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.