11

我正在尝试弄清楚 syncAdapter 的工作原理,我使用 sampleSync Adapter 作为示例/起点,并以此为基础进行了第一次测试。唯一的区别是我没有使用默认联系人提供程序,而是我需要自己的一个。

此方法与 sampleSyncAdapter 演示(在 AccountAuthenticatorActivity 中)中的方法有点相同,我刚刚添加了定期同步。

    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();
}

在 perfomSync() 方法中,我有以下方法:

    @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");
}

这里我只是调用了一个简单的 SAP webservice 并在日志中显示出来。现在我有以下两个问题:

  1. 当我在设置中添加我的帐户时,SYNC 不会自动启动。我需要进入帐户并选中复选框以开始同步?
  2. 在此示例中,同步不是每 30 秒触发一次...我是否需要在 perfomSync() 方法中添加一些内容才能让系统知道同步已完成并且可以开始下一次运行?

目前我没有在 contentProvider 中写入值,只是因为我试图弄清楚同步是如何详细工作的。

目前我正在Android模拟器上进行测试。

提前感谢您的反馈。

亲切的问候,

罗宾

4

7 回答 7

13

我也在努力与同步适配器进行定期同步。我可以使用 requestSync 手动触发我的 SyncAdapter,但 addPeriodicSync 不会触发。

我注意到在所有示例中,进入 Settings->Accounts 显示 SyncAdapter 的帐户带有一个小“同步轮”(如果同步正常,通常为绿色;如果最近同步失败,则为红色)以及“上次同步”时间戳. 我的帐户(从Google Docs复制和粘贴的虚拟帐户)没有列出同步轮或时间戳之类的任何内容。

进一步挖掘发现了问题所在:我的内容提供者在其 XML 中没有标签(我以前使用它没有问题,所以我浏览了文档的那部分)。为我的内容提供者添加一个简单的标签会导致它在设置中显示在我的帐户下,同时还有一个同步轮和时间戳。

这是从我的应用程序中获取的一些代码以获得灵感。希望它会帮助某人,某处!

/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(内容提供者需要标签才能显示在帐户中)

<?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>

主要活动。我在首次运行设置向导之后调用此代码,但您可以在任何地方调用它。这将尝试每30 秒同步一次(用于测试)。请注意,谷歌文档目前是错误的,因为它提到它需要毫秒而不是秒。要注意的另一件事是,您不能将 null 作为捆绑传递。这样做会抛出 IllegalArgumentException 或类似的东西。

//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);
于 2014-10-08T19:35:16.683 回答
13

如果未设置同步选项,则某些设备不会触发定期同步。我最近对三星 Galaxy Grand 2 的这个问题发疯了……

在此处输入图像描述

于 2014-12-06T07:07:41.720 回答
5

我只是把头撞在墙上好几个小时,试图弄清楚为什么定期同步不起作用。事实证明,轮询频率需要以秒(字面意思)而不是毫秒为单位,也不是以毫秒为单位的秒数。因此,例如,如果您希望它每分半钟同步一次,您需要调用:

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

此外,传入的包不能像文档中那样为空,它会抛出 NullPointerException。

于 2014-07-25T16:09:07.430 回答
1

仅当其自动同步设置为 ON 且 syncable=true 时,才能运行定期同步。解决此问题的更好方法是使用GCM。只要客户端需要了解更改,服务器就可以向设备发送推送通知。在客户端,我们会在收到此类消息后手动请求同步。它的电池效率更高,我们会在服务器一上线就更新,无需等待下一个同步周期。

于 2013-11-22T21:48:02.323 回答
1

即使您的所有同步配置都以正确的方式设置,如果设备内部存储空间几乎已满,则定期同步将不起作用。我认为如果使用了 96% 或 97% 的内存,同步将停止运行。我不知道是他们的即使内存几乎已满,任何使其工作的规定。您可以在 android mobile 的 gmail 应用程序中观察到相同的问题,当内存快满时同步将无法工作。当设备内存快满时,您无法使用 android gmail 应用程序接收或发送消息。

于 2017-03-07T09:12:09.213 回答
1

这对我来说很好 就解释如何使 addPeriodicSync 工作而言,培训指南中有两个错误:

  1. 您必须调用 ContentResolver.setSyncAutomatically 并将 true 作为第三个(同步)参数,以便在 addPeriodicSync 之前为您的适配器启用同步。像这样: ContentResolver.setSyncAutomatically(account,MY_AUTHORITY,true);

  2. ContentResolver.addPeriodicSync 的第四个(pollFrequency)参数是秒数,如此处所述,而不是培训指南中暗示的毫秒数。培训指南中 addPeriodicSync 的演示代码将导致每千小时同步一次,而不是每小时一次。所以最小频率是1分钟。

请参阅此http://digitalassassin.net/2014/03/contentresolver-addperiodicsync-doesnt-work-never-syncs/

于 2018-03-09T07:22:52.073 回答
-1

尝试android:process=":sync"从 android manifest 中删除以在中文 rom 中运行

于 2020-08-17T06:57:50.047 回答