Marshmallow及以上版本SyncAdapter同步失效问题求助
onPerformSync() Not Triggering on Android 6.0+ (Marshmallow+) Got it, let's break down why your SyncAdapter's onPerformSync() isn't firing on Marshmallow and newer versions, and fix it step by step. This is a common issue tied to API 23+ permission changes, sync request behavior, and background optimizations.
1. Fix Permissions First
Android 6.0 introduced critical changes to how permissions work, and SyncAdapter relies on specific permissions that might have been overlooked:
- Declare required permissions in
AndroidManifest.xml:<!-- Required for modifying sync settings --> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> <!-- If your sync uses accounts, add this (requires dynamic request on API23+) --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - Handle
GET_ACCOUNTSdynamically: Since this is a dangerous permission on API23+, you need to request user consent before attempting sync. UseActivityCompat.requestPermissions()to prompt the user for access.
2. Use the Updated requestSync() API
The old requestSync(Account, String, Bundle) method is deprecated and restricted on API23+. Switch to the SyncRequest.Builder pattern to build valid sync requests:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { SyncRequest syncRequest = new SyncRequest.Builder() .setSyncAdapter(yourAccount, YOUR_CONTENT_AUTHORITY) .setExtras(yourSyncExtrasBundle) .setManual(true) // Marks this as a user-initiated sync (bypasses system restrictions) .build(); ContentResolver.requestSync(syncRequest); } else { // Fallback for older Android versions ContentResolver.requestSync(yourAccount, YOUR_CONTENT_AUTHORITY, yourSyncExtrasBundle); }
The setManual(true) flag is crucial here—it tells the system this is an explicit sync request, which is less likely to be blocked by background limits.
3. Verify Sync Settings Are Enabled
On API23+, users or system settings might disable sync for your app. Add checks to ensure sync is active before requesting it:
// Check if global sync is enabled system-wide boolean isGlobalSyncEnabled = ContentResolver.getMasterSyncAutomatically(); // Check if sync is enabled for your app's authority/account boolean isAppSyncEnabled = ContentResolver.getSyncAutomatically(yourAccount, YOUR_CONTENT_AUTHORITY); if (!isGlobalSyncEnabled || !isAppSyncEnabled) { // Enable sync for your app (requires WRITE_SYNC_SETTINGS permission) ContentResolver.setSyncAutomatically(yourAccount, YOUR_CONTENT_AUTHORITY, true); // Optional: Prompt the user to enable global sync if needed }
4. Check SyncAdapter Configuration
Double-check your syncadapter.xml to ensure it's compatible with API23+:
- Set
android:userVisible="true": If this is set tofalse, the system might block sync requests on newer versions (invisible syncs face stricter background limits). - Confirm
android:contentAuthorityexactly matches what you're using in yourArticleProviderand sync requests.
Example validsyncadapter.xml:
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.your.app.articleprovider" android:accountType="com.your.app.accounttype" android:userVisible="true" android:supportsUploading="true" android:allowParallelSyncs="false" />
5. Bypass Background Optimization (Doze/App Standby)
Marshmallow's Doze mode and App Standby can delay or block background syncs. If you need immediate sync:
- Request battery optimization exemption: Add this permission to your manifest:
Then prompt the user to allow your app to bypass battery restrictions:<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Note: Only use this if your sync is time-sensitive—users might be wary of granting this permission.if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (!powerManager.isIgnoringBatteryOptimizations(getPackageName())) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } }
6. Validate Account Existence
Ensure the account you're using for sync is properly registered with AccountManager. On API23+, if the account doesn't exist, the sync request will fail silently. Use AccountManager.getAccountsByType() to check if your account is present before requesting sync.
Start with steps 1-3 first—those are the most common fixes for this issue. If you still have problems, move on to checking your SyncAdapter config and background optimizations.
内容的提问来源于stack exchange,提问作者Sackurise

