Android syncadapter will not synchronize Samsung S6 edge plus nougat on my device (periodically when API < = 23)

I have a problem using syncadapter. The strangest thing about it is that it worked earlier, but now synchronization is only effective when I call it manually

It also does not apply to simulators (API 24)

This is my sync adapter code:

 public class SmogAppSyncAdapter extends AbstractThreadedSyncAdapter {

private static final String LOG_TAG = SmogAppSyncAdapter.class.getSimpleName();

public static final int SYNC_INTERVAL =  60; // 60 * 60 = 1h to the nearest 20min.
public static final int SYNC_FLEXTIME = SYNC_INTERVAL / 3;
public static final int POLLUTION_DISTANCE = 10000; //preferred distance between prefs location and nearest measurement point
private static final int POLLUTION_NOTIFICATION_ID = 0;

private ContentResolver mContentResolver;
private SharedPreferences prefs;
private Context syncContext;
private int prefsPollutionLevel;
private double prefsHomeLocationLatitude;
private double prefsHomeLocationLongitude;
private boolean prefsNewMessageNotification;
private int currentApiPollutionLevel;
private Float currentApiPollutionLevelLatitude;
private Float currentApiPollutionLevelLongitude;


/**
 * Set up the sync adapter
 */
SmogAppSyncAdapter(Context context, boolean autoInitialize) {
    super(context, autoInitialize);
    /*
     * If your app uses a content resolver, get an instance of it
     * from the incoming Context
     */
    mContentResolver = context.getContentResolver();
    prefs = PreferenceManager.getDefaultSharedPreferences(context);
    syncContext = context;
    prefsHomeLocationLatitude = prefs.getFloat(syncContext.getResources().getString(R.string.pref_key_home_latitude), 0f);
    prefsHomeLocationLongitude = prefs.getFloat(syncContext.getResources().getString(R.string.pref_key_home_longitude), 0f);
    prefsNewMessageNotification = prefs.getBoolean(syncContext.getResources().getString(R.string.pref_key_notification_new_message), true);
    prefsPollutionLevel = Integer.valueOf(prefs.getString(syncContext.getResources().getString(R.string.pref_key_pollution_level_list), "0"));
}

@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {

    // fetching remote data and insert some stuff

    Log.d(LOG_TAG, "onPerformSync was called");

}

/**
 * Helper method to schedule the sync adapter periodic execution
 */
private static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
    Account account = getSyncAccount(context);
    String authority = context.getString(R.string.content_authority);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      //   we can enable inexact timers in our periodic sync
        SyncRequest request = new SyncRequest.Builder().
                syncPeriodic(syncInterval, flexTime).
                setSyncAdapter(account, authority).
                setExtras(new Bundle()).build();
        ContentResolver.requestSync(request);
    } else {
    ContentResolver.addPeriodicSync(account,
            authority, new Bundle(), syncInterval);
    }
}

/**
 * Helper method to have the sync adapter sync immediately
 *
 * @param context The context used to access the account service
 */
private static void syncImmediately(Context context) {
    Bundle bundle = new Bundle();
    bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    ContentResolver.requestSync(getSyncAccount(context),
            context.getString(R.string.content_authority), bundle);
}

/**
 * Helper method to get the fake account to be used with SyncAdapter, or make a new one
 * if the fake account doesn't exist yet.  If we make a new account, we call the
 * onAccountCreated method so we can initialize things.
 *
 * @param context The context used to access the account service
 * @return a fake account.
 */
public static Account getSyncAccount(Context context) {
    Log.d(LOG_TAG, "getSyncAccount");
    // Get an instance of the Android account manager
    AccountManager accountManager =
            (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);

    // Create the account type and default account
    Account newAccount = new Account(
            context.getString(R.string.app_name), context.getString(R.string.sync_account_type));

    // If the password doesn't exist, the account doesn't exist
    if (null == accountManager.getpassword(newAccount)) {

    /*
     * Add the account and account type, no password or user data
     * If successful, return the Account object, otherwise report an error.
     */
        if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
            Log.d(LOG_TAG, "return null");
            return null;
        }
        /*
         * If you don't set android:syncable="true" in
         * in your <provider> element in the manifest,
         * then call ContentResolver.setIsSyncable(account, AUTHORITY, 1)
         * here.
         */

        onAccountCreated(newAccount, context);
    }
    else {
        Log.d(LOG_TAG, "If the password doesn't exist, the account doesn't exist");
    }
    Log.d(LOG_TAG, "Account name: " + newAccount.name);
    return newAccount;
}

private static void onAccountCreated(Account newAccount, Context context) {
    Log.d(LOG_TAG, "onAccountCreated");
    /*
     * Since we've created an account
     */
    SmogAppSyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);

    /*
     * Without calling setSyncAutomatically, our periodic sync will not be enabled.
     */
    ContentResolver.setIsSyncable(newAccount, context.getString(R.string.content_authority), 1);
    ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.content_authority), true);

    /*
     * Finally, let's do a sync to get things started
     */
  //  syncImmediately(context);
}

public static void initializeSyncAdapter(Context context) {
    Log.d(LOG_TAG, "inside initializeSyncAdapter");
    getSyncAccount(context);
}

}

My services:

public class SmogAppSyncService extends Service {

private static SmogAppSyncAdapter sSyncAdapter = null;
private static final Object sSyncAdapterLock = new Object();


@Override
public void onCreate() {
    synchronized (sSyncAdapterLock) {
        sSyncAdapter = new SmogAppSyncAdapter(getApplicationContext(), true);
    }
}

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

}

In my list, I added:

 <service android:name=".services.sync.SmogAppAuthenticatorService">
        <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=".services.sync.SmogAppSyncService"
        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/syncadapter" />
    </service>

And permissions:

    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

Here are my other XML files:

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/content_authority"
android:accountType="@string/sync_account_type"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true" />

Authetnicator.xml

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/sync_account_type"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:smallIcon="@mipmap/ic_launcher" />

If it works, I can provide more details. I really stick to this question and check some answers in stackoverflow. It doesn't help me. Is there any way to make this work? Periodic synchronization applies to simulators, but not to real devices

Update: I've read the snooze mode that may be the cause, but it's not my case, or I'm just misconfigured. Basically, snooze mode and its battery optimization can disable some background tasks on the device

resolvent:

Javadoc from syncrequest.builder#syncperiodic (long, long):

 /**
     * Build a periodic sync.
     ...
     * @param pollFrequency the amount of time in seconds that you wish
     *            to elapse between periodic syncs. A minimum period of 1 hour is enforced.
     ...
     */
    public Builder syncPeriodic(long pollFrequency, long beforeSeconds) {
        ...
    }

Please note that it declares to enforce a minimum periodic synchronization timeout of 1 hour. This may be your problem

But since then? I've never heard of such a long timeout before. Let's study it in depth

I ran the following command:

$cd ~/aosp/frameworks/base
$find ./ -name SyncRequest.java | xargs git blame | grep "A minimum period of 1 hour is enforced"

Get this result:

e96c3b7eff52 (Shreyas Basarge  2016-01-29 19:25:51 +0000 310)          *            to elapse between periodic syncs. A minimum period of 1 hour is enforced.

It seems that the submission began in January 2016. This explains why it applies to API 19 but not to API 25

I further verified this submission and added code to increase the minimum timeout from 60 seconds to 1 hour

Then you may ask why Google developers change the semantics of the working APIs that many applications rely on without giving developers appropriate notice? The answer is the same as usual - because they can

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>