SyncAdapter onPerformSync()在模拟器上调用,但在物理设备上运行时则不会

时间:2014-03-26 23:37:08

标签: android-syncadapter

我已关注Google's tutorial使用带有 dummyAccount 的SyncAdapter和 no ContentProvider。

本教程非常简单,我知道使用帐户和ContentProvider的存根的限制。我实现了它,当在模拟器上运行时,它工作得非常好。我在日志中看到了periodicSync(..)定期调用的消息,以及我特意要求requestSync(..)调用的消息。

这是令人兴奋的部分,当我在我的BQ 5 HD(Android 4.1.2)上运行应用程序时,SyncAdapter 从未调用。如果重新安装了应用程序,但似乎没有发生任何事情。我浪费了几个星期的时间,我无法理解。

这是我的 manifestFile

<?xml version="1.0" encoding="utf-8"?>

<uses-sdk
    android:minSdkVersion="10"
    android:targetSdkVersion="18" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    ....Whole bunch of activities...

    <provider
        android:name="com.sf.app_name.stubs.StubProvider"
        android:authorities="com.sf.app_name.provider"
        android:exported="false"
        android:syncable="true" />

    <service android:name="com.sf.app_name.stubs.AuthenticatorService" 
               android:exported="false">
        <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.sf.app_name.sync.SyncService"
        android:exported="false"
        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>

</application>

authenticator.xml

    <?xml version="1.0" encoding="utf-8"?>
 <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
                       android:accountType="com.sf.app_name"
                       android:userVisible="false" />

syncadapter.xml

    <?xml version="1.0" encoding="utf-8"?>
 <sync-adapter
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="com.sf.app_name.provider"
        android:accountType="com.sf.app_name"
        android:userVisible="false"
        android:supportsUploading="false"
        android:allowParallelSyncs="true"
        android:isAlwaysSyncable="true"/>

非常感谢输入。

1 个答案:

答案 0 :(得分:4)

感谢老忠实的Log.d(...),终于找出了什么是错的。这是一个明确的noob错误,我发布了答案,以防止其他初学者犯同样的错误。

在我创建和添加SyncAdapter框架所需的“dummyAccount”的代码中,我执行了以下操作:

  Account[] accounts = accountManager.getAccounts();
    if(accounts.length == 0){
        Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
        ContentResolver.setIsSyncable(newAccount, AUTHORITY, 1);
        ContentResolver.setSyncAutomatically(newAccount, AUTHORITY, true);  
        ContentResolver.addPeriodicSync(newAccount, AUTHORITY, new Bundle(), 40l);
        accountManager.addAccountExplicitly(newAccount, null, null);
        Log.d("serverSync", "ContetResolver set periodic sync");
    }

方法getAccounts()会返回与设备关联的所有帐户显然它会在模拟器中运行时返回ZERO,因为模拟器没有任何关联的帐户。所以我认为除此之外要做到这一点。我创建了ACCOUNT_TYPE类型的帐户添加它,然后快速地沿着我的方向前进。 (顺便说一下,addPeriodicSyncsetIsSyncable之上setSyncAutomatially的原因是解决与另一事项有关的problem

当然,我的APP的SyncAdapter在执行以下操作时被调用:

ContentResolver.requestSync(signedInAccountInstance.getDummyAccount(),
                               AccountManagerActivity.AUTHORITY, bundle);

他们getDummyAccount(..)被这样得到了:

 Account[] accounts = accountManager.getAccounts();
 return accounts[0];

当在实际的物理设备上运行时,我应该已经意识到 getAccounts(..)也会返回(至少)与我的Android设备关联的Gmail帐户。因此当我做的时候

ContentResolver.requestSync(signedInAccountInstance.getDummyAccount(),
                               AccountManagerActivity.AUTHORITY, bundle);

发送的“dummyAccount”将是Google的AccountType,因此我的应用 SyncAdapter 永远不会被调用。相反,是gmail应用程序的SyncAdapter被我的捆绑调用。 我怎么发现这个?通过在设置&gt;帐户下查看我的物理设备的帐户后在日志中打印出我的dummyAccount,并意识到由于某些原因我在移动设备上执行我的应用程序时,我的Gmail帐户会显示“同步错误”。

第一次做正确的事情可以防止这一切:

Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);

ACCOUNT_TYPE是我的应用中使用的静态最终变量。

    // An account type, in the form of a domain name
public static final String ACCOUNT_TYPE = "com.sf.app_name";

希望这有助于拯救某些人头痛。