【问题标题】:SyncAdapter periodicsync() not triggeringSyncAdapter 周期性同步()未触发
【发布时间】:2013-03-26 07:52:58
【问题描述】:

我正在尝试弄清楚 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 模拟器上进行测试。

提前感谢您的反馈。

亲切的问候,

罗宾

【问题讨论】:

标签: android android-contentprovider android-syncadapter


【解决方案1】:

我还在努力与同步适配器进行定期同步。我可以使用 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);

【讨论】:

  • 这仅适用于特定的 Android 版本吗?我在这里的所有设备上都进行了同步,除了客户端上的一些设备外,内容提供商上没有标签。而且我不想发布无法解决任何问题的版本。
  • @DalvikVM 它可能在没有标签的情况下工作,如果它对你有用,我不会修复没有损坏的东西。我正在使用一组特定的三星 Android 平板电脑,这似乎是让它工作的原因。
  • @wwlshk91:在客户端的某些平板电脑上坏了。这些是运行 Android 4.1.2 的三星 Galaxy Notes 10.1。将这些平板电脑更新到 4.4 有帮助吗?
  • @DalvikVM 抱歉耽搁了。我知道以上内容适用于许多运行 4.4 的三星机型,并且我在至少一款运行 4.3 的机型上成功测试了它。我可以追溯到 4.2,但我的应用程序的许多组件需要 Jelly Bean 或更高版本,所以我没有再降低。
  • 我的问题原来与三星的具体问题无关。这是我自己的一个(愚蠢的)错误。我搜索了帐户但没有检查类型,所以在一些随机平板电脑上我得到了一个非谷歌帐户。见stackoverflow.com/q/31290783/2072569
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 最合乎逻辑的答案之一
        【解决方案6】:

        这个对我来说很好用 在解释如何使 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/

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-10-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多