我在使用SyncAdapter時遇到了問題。最奇怪的是,它是早期工作,但現在只有手動調用它才能同步。Android SyncAdapter不會在我的設備上同步Samsung S6 Edge Plus Nougat(API <= 23時定期同步)
這還不算在模擬器(API 24)
這裏工作是我的同步適配器的代碼:
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);
}
}
我的服務:
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();
}
}
在我的表現,我增加那些:
<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>
和權限:
<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" />
這裏是我的其他XML文件:
<?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" />
我可以提供更多的細節,如果它會b有幫助。我真的堅持這個問題,並檢查了一些在stackoverflow答案。對我沒有幫助。有什麼方法可以完成這項工作?週期性同步適用於仿真器,但不適用於真實設備。
更新:我已閱讀關於打盹模式,可能是原因,但它不是在我的情況下,或者我剛剛配置了錯誤的東西。 基本打盹模式與其電池優化可以禁用設備上的一些後臺任務。
真實設備的品牌是什麼?我在Xiaomi設備中遇到類似這樣的問題。 –
我的設備是三星Galaxy 6邊緣加,它以前工作,但不是現在 – Konrad
我發現,這個問題只出現在我的手機到目前爲止,我有三星Galaxy S6邊緣加Android Nougat版本 – Konrad