首页 > 解决方案 > 同步适配器周期同步不起作用 - 为什么?

问题描述

我已经尝试了两天没有休息,但我的同步适配器在请求定期同步后永远不会触发。请求的同步间隔为 30 秒,但即使在 logcat 配置中更改为 NO-FILTER 后,也不会调用 onperform。请看下面的代码,请帮忙。我一直在努力解决这个问题,没有希望。虽然在android设置账号下创建成功,但是可以通过刷新手动同步成功。

AbstractThreadedSyncAdapter 类

public class ServiceSyncAdapter extends AbstractThreadedSyncAdapter {

    //TODO change this constant SYNC_INTERVAL to change the sync frequency
    public static final int SYNC_INTERVAL               = 30; //60 * 180;       // 60 seconds (1 minute) * 180 = 3 hours
    public static final int SYNC_FLEXTIME               = SYNC_INTERVAL/2;
    private static final int MOVIE_NOTIFICATION_ID      = 3004;

    public ServiceSyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
        Log.i(AppUtils.LOG_TAG, "onPerformSync");
        //TODO get some data from the internet, api calls, etc.
        //TODO save the data to database, sqlite, couchbase, etc
        //notifyDataDownloaded();
    }

    /**
     * Send the notification message to the status bar
     */
    /*private void notifyDataDownloaded() {
        Context context = getContext();
        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(context)
                        .setSmallIcon(android.support.v7.appcompat.R.drawable.notification_template_icon_bg)
                        .setContentTitle("Sync Adapter")
                        .setContentText("New Data Available!");

        // Opening the app when the user clicks on the notification.
        Intent resultIntent = new Intent(context, MainActivity.class);

        // The stack builder object will contain an artificial back stack for the started Activity.
        // This ensures that navigating backward from the Activity leads out of your application to the Home screen.
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(resultPendingIntent);

        NotificationManager mNotificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(MOVIE_NOTIFICATION_ID, mBuilder.build()); // MOVIE_NOTIFICATION_ID allows you to update the notification later on.
    }*/


    /**
     * Helper method to schedule the sync adapter periodic execution
     */
    public 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);
        }
        //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
     */
    public static void syncImmediately(Context context) {
        Log.i(AppUtils.LOG_TAG, "syncImmediately");
        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) {

        AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); // Get an instance of the Android account manager
        Account newAccount = new Account(context.getString(R.string.app_name), context.getString(R.string.sync_account_type)); // Create the account type and default account

        // If the password doesn't exist, the account doesn't exist
        if (accountManager.getPassword(newAccount) == null) {
            if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
                Log.e(AppUtils.LOG_TAG, "getSyncAccount Failed to create new account.");
                return null;
            }
            onAccountCreated(newAccount, context);
        }
        return newAccount;
    }

    private static void onAccountCreated(Account newAccount, Context context) {
        Log.i(AppUtils.LOG_TAG, "onAccountCreated");

        //ContentResolver.setMasterSyncAutomatically(true);
        //ContentResolver.setIsSyncable(newAccount, context.getString(R.string.content_authority), 1);

        ServiceSyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);

        ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.content_authority), true);





        syncImmediately(context);
    }

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

和服务类

public class ServiceSync extends Service {

    private static final Object sSyncAdapterLock = new Object();
    private static ServiceSyncAdapter myServiceSyncAdapter = null;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(AppUtils.LOG_TAG, "onCreate ServiceSync");
        synchronized (sSyncAdapterLock) {
            if (myServiceSyncAdapter == null) {
                myServiceSyncAdapter = new ServiceSyncAdapter(getApplicationContext(), true);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(AppUtils.LOG_TAG, "onBind ServiceSync");
        return myServiceSyncAdapter.getSyncAdapterBinder();
    }
}

身份验证器服务类

public class AuthenticatorService extends Service {

    private AccountAuthenticator mAuthenticator;

    @Override
    public void onCreate() {
        Log.d(AppUtils.LOG_TAG, "onCreate");
        // Create a new authenticator object
        mAuthenticator = new AccountAuthenticator(this);
    }

    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(AppUtils.LOG_TAG, "onBind");
        return mAuthenticator.getIBinder();
    }

}

验证器类

public class AccountAuthenticator extends AbstractAccountAuthenticator {

    public AccountAuthenticator(Context context) {
        super(context);
    }

    // No properties to edit.
    @Override
    public Bundle editProperties(
            AccountAuthenticatorResponse r, String s) {
        throw new UnsupportedOperationException();
    }

    // Because we're not actually adding an account to the device, just return null.
    @Override
    public Bundle addAccount(
            AccountAuthenticatorResponse r,
            String s,
            String s2,
            String[] strings,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }

    // Ignore attempts to confirm credentials
    @Override
    public Bundle confirmCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }

    // Getting an authentication token is not supported
    @Override
    public Bundle getAuthToken(
            AccountAuthenticatorResponse r,
            Account account,
            String s,
            Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }

    // Getting a label for the auth token is not supported
    @Override
    public String getAuthTokenLabel(String s) {
        throw new UnsupportedOperationException();
    }

    // Updating user credentials is not supported
    @Override
    public Bundle updateCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            String s, Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }

    // Checking features for the account is not supported
    @Override
    public Bundle hasFeatures(
            AccountAuthenticatorResponse r,
            Account account, String[] strings) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
}

清单文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.international.sonet.eac5">

    <uses-permission android:name="android.permission.INTERNET" />

    <uses-permission android:name="android.permission.READ_SYNC_STATS"/>
    <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"/>


    <application
        android:name="android.support.multidex.MultiDexApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher_round"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".HomeActivity"
            android:label="@string/title_activity_news"
            android:theme="@style/AppTheme.NoActionBar" />

        <provider
            android:authorities="@string/content_authority"
            android:name="com.international.sonet.services.StubProvider"
            android:exported="false"
            android:syncable="true" />


        <!-- SyncAdapter's dummy authentication service -->
        <service android:name="com.international.sonet.services.AuthenticatorService">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>
            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator" />
        </service>

        <!-- The SyncAdapter service -->
        <service
            android:name="com.international.sonet.services.ServiceSync"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="android.content.SyncAdapter" />
            </intent-filter>
            <meta-data
                android:name="android.content.SyncAdapter"
                android:resource="@xml/syncadapter" />
        </service>

    </application>

</manifest>

验证器 xml 文件

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="@string/sync_account_type"
    android:icon="@android:drawable/ic_dialog_info"
    android:label="@string/app_name"
    android:smallIcon="@android:drawable/ic_dialog_info" />

同步适配器 xml 文件

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

我正在像这样从家庭活动 oncreate() 初始化我的适配器

ServiceSyncAdapter.initializeSyncAdapter(getApplicationContext());

ProviderStub 扩展了 ContentProvider

标签: android

解决方案


推荐阅读