SyncAdapter periodicsync() not triggering
Asked Answered
O

7

11

I'm trying ty figure out how the syncAdapter works, I used the sampleSync Adapter as an example/starting point and I based my first test on it. The only difference is that I'm not working with the default contacts provider, but that I need one of my own.

This method is kinda the same as in the sampleSyncAdapter demo (in AccountAuthenticatorActivity), i've just added the periodic sync.

    public void finishLogin(String authToken) {
    Log.i(TAG, "finishLogin()");
    final Account account = new Account(mUsername, "be.company.syncAdapterTest");
    if(mRequestNewAccount) {
        mAccountManager.addAccountExplicitly(account, mPassword, null);
        ContentResolver.setIsSyncable(account, MY_AUTHORITY, 1);

        Bundle params = new Bundle();
        params.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
        params.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false);
        params.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);           
        ContentResolver.addPeriodicSync(account, MY_AUTHORITY, params, 30);
        ContentResolver.setSyncAutomatically(account, MY_AUTHORITY, true);
        ContentResolver.requestSync(account,MY_AUTHORITY,params);
    } else {
        mAccountManager.setPassword(account, mPassword);
    }
    final Intent intent = new Intent();
    intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, "ACCOUNT_TEST");
    intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, "be.company.syncAdapterTest");
    setAccountAuthenticatorResult(intent.getExtras());
    setResult(RESULT_OK, intent);
    finish();
}

In the perfomSync() method i have the following method:

    @Override
public void onPerformSync(Account account, Bundle extras, String authority,
        ContentProviderClient provider, SyncResult syncResult) {
    Log.d(TAG, "onPerformSync() start");
    // Testje
    try {
        final String authToken = mAccountManager.blockingGetAuthToken(account, "be.company.syncAdapterTest", NOTIFY_AUTH_FAILURE);
        Log.d(TAG, SAPNetworkUtilities.getWeek(account, authToken, getRandomDate()));
    } catch (OperationCanceledException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (AuthenticatorException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Log.d(TAG, "onPerformSync() end");
}

Here I just call a simple SAP webservice and show it in the log. Now I have following two questions:

  1. The SYNC is not started automatically when I add my Account in the settings. I need to go inside the account and check the checkbox to start the sync?
  2. The sync is not triggerd every 30 seconds in this example... Do I need to add something in the perfomSync() method in order to let the system know that the sync is done and that the next run can start?

At this moment i do not write the values in the contentProvider, just because i'm trying to figure out how the sync works in detail.

Currently I'm testing on the Android emulator.

Thanks in advance for your feedback.

Kind regards,

Robin

Overhead answered 26/3, 2013 at 7:52 Comment(2)
possible duplicate of Why does ContentResolver.requestSync not trigger a sync?Guntar
I set a periodicSync with frequency <60s, and saw a logcat message that the system had rounded it up to 60s - a minimum not mentioned in the documentation. Of course, I wouldn't be reading this page if it had then gone on actually to sync at all - periodicSync didn't work for me either, regardless of setIsSyncable or #7926302Backset
C
13

I was also struggling with periodic syncing with the sync adapter. I could fire my SyncAdapter manually with requestSync, but addPeriodicSync would not fire.

I noticed that in all of the examples, going into Settings->Accounts showed the SyncAdapter's account with a little "sync wheel" (usually green if it's syncing fine; red if it failed to sync recently) along with a "Last Synced" timestamp. My account (a dummy account copied and pasted from the Google Docs) didn't have anything like a sync wheel or timestamp listed.

Further digging exposed what turned out to be the problem: my content provider didn't have a label in it's XML (I was using it previously with no problems, so I skimmed through that part of the documentation). Adding a simple label for my content provider caused it to show up under my account in the Settings, along with a sync wheel and timestamp.

Here's some code taken from my app for inspiration. Hopefully it will help someone, somewhere!

/res/xml/sync_adapter.xml

<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.example.database"
android:allowParallelSyncs="false"
android:contentAuthority="com.example.database.data.provider"
android:isAlwaysSyncable="true"
android:supportsUploading="false"
android:userVisible="true" />

/com/example/database/data/MySyncAdapter

public class MySyncAdapter extends AbstractThreadedSyncAdapter {
    private static final String TAG = MySyncAdapter.class.getSimpleName();
    Context context;

    public MySyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
        this.context = context;
    }

    public MySyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
        super(context, autoInitialize, allowParallelSyncs);
        this.context = context;
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
        Log.e(TAG, "Performing Sync");
    }
}

AndroidManifest.xml (NEEDS Label for Content Provider to show up in Accounts)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.database">

    <uses-sdk tools:node="replace" />

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_STATS" />


    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:logo="@drawable/chef_collection_logo_white"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <provider
            android:name="com.example.database.data.MyContentProvider"
            android:authorities="com.example.database.data.provider"
            android:label="my provider"
            android:exported="false"
            android:multiprocess="true"
            android:syncable="true" />

        <activity
            android:name=".app.MainActivity"
            android:label="@string/title_activity_main">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name="com.example.database.data.AuthenticatorService"
            android:exported="true"
            android:process=":auth">
            <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="com.example.database.data.MySyncAdapterService"
            android:exported="true"
            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>

    </application>

</manifest>

MainActivity. I call this code after the first-run setup wizard, but you can call it anywhere. This will attempt to sync every 30 seconds (used for testing). Note that the Google Docs for this are currently wrong, as it mentions that it wants milliseconds instead of seconds. Another thing to note is that you cannot pass null as a bundle. Doing so will throw an IllegalArgumentException or something similar.

//Create Account
mAccount = createSyncAccount(this);


//Turn on periodic syncing
ContentResolver resolver = getContentResolver();
resolver.setIsSyncable(mAccount, AUTHORITY, 1);
resolver.setSyncAutomatically(mAccount, AUTHORITY, true);

resolver.addPeriodicSync(
        mAccount,
        AUTHORITY,
        Bundle.EMPTY,
        30);
Cutter answered 8/10, 2014 at 19:35 Comment(6)
Is this only on specific Android versions? I got my sync working on all the devices here without a label on the content provider except for some at the client. And I don't want to make a release which fixes nothing.Bobstay
@DalvikVM It's possible that it works without a label and, if it's working for you, I wouldn't fix what ain't broken. I was working with a specific set of Samsung Android tablets and this is what seemed to get it working.Cutter
@wwlshk91: It is broken on some tablets of the client. These are Samsung Galaxy Notes 10.1 running Android 4.1.2. Wil updating these tablets to 4.4 help?Bobstay
@DalvikVM Sorry for the delay. I know the above works with many Samsung models running 4.4 and I tested it successfully on at least one model with 4.3. I was able to go as far back as 4.2, but many of the components of my app needed Jelly Bean or higher, so I didn't go any lower.Cutter
My problems turned out to have nothing to do with Samsung specific things. It was a (stupid) mistake of my own. I searched for accounts but did not check for the type, so on some random tablets I got a non-google account. See https://mcmap.net/q/1017790/-custom-sync-not-working-with-google-account-com-google-on-some-samsung-devices/2072569.Bobstay
ContentResolver.setSyncAutomatically(mAccount, AUTHORITY, true); is what I was missing. ThanksJoycejoycelin
K
13

Periodic Sync does not trigger in some devices if sync option is not set. I went crazy with this issue with a Samsung Galaxy Grand 2 recently...

enter image description here

Kilogrammeter answered 6/12, 2014 at 7:7 Comment(0)
C
5

I just banged my head against a wall for hours trying to figure out why periodic sync wasn't working. It turns out that the poll frequency needs to be in seconds (literal) not milliseconds, and not seconds in milliseconds. So, for example, if you want it to sync every minute and a half, you would need to call:

            ContentResolver.addPeriodicSync(
                    account,
                    authority,
                    Bundle.EMPTY,
                    90
            );

Also, the bundle passed in cannot be null as it is in the documentation, it will throw a NullPointerException.

Cohbath answered 25/7, 2014 at 16:9 Comment(0)
C
2

Periodic syncing will not work if the device internal storage is almost full, even if all your syncing configurations are set in the right way.I think syncing will stop functioning if 96 or 97% of memory is used.I don't know is their any provision to make it working even if memory is almost full. You can observe the same issue in gmail application in android mobile, where the sync will not work when memory is almost full.You can't receive or send message using android gmail application when device memory is almost full.

Collegium answered 7/3, 2017 at 9:12 Comment(1)
one of the most logical answersHellkite
T
1

A periodic sync can only be run if its auto-sync setting is ON and it’s syncable=true. A better approach to this problem will be to use GCM. The server can send push notification to the device(s) whenever there’s a change the client needs to know about. On the client, we request a sync manually upon receiving such message. It’s more battery efficient and we get updated as soon as our server is, without waiting for the next sync cycle.

Topflight answered 22/11, 2013 at 21:48 Comment(0)
A
1

This one works fine for me There are two mistakes in the training guide as far as explaining how to make addPeriodicSync work:

  1. You must call ContentResolver.setSyncAutomatically with true as the third (sync) parameter to enable syncing for your adaptor before addPeriodicSync. like this : ContentResolver.setSyncAutomatically(account,MY_AUTHORITY,true);

  2. The fourth (pollFrequency) parameter of ContentResolver.addPeriodicSync is a number of seconds, as stated here, and not milliseconds, as implied in the training guide. The demo code for addPeriodicSync in the training guide will cause a sync once every thousand hours instead of once an hour. So the minimum frequency is 1 minute.

Refer To this http://digitalassassin.net/2014/03/contentresolver-addperiodicsync-doesnt-work-never-syncs/

Ardellearden answered 9/3, 2018 at 7:22 Comment(0)
I
-1

Try to remove android:process=":sync" from android manifest to run in chinese roms

Imagine answered 17/8, 2020 at 6:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.