如何在没有SyncAdapter的情况下在Android上实施帐户

Jos*_*arl 9 android user-accounts accountmanager android-syncadapter android-wake-lock

我正在使用内置帐户系统(使用AccountManager API)为Android应用程序实现登录系统.

在Android 2.2+上一切都很好,但在Android 2.1上不包括SyncAdapter导致在帐户设置屏幕中重新启动(请参阅http://code.google.com/p/android/issues/detail?id=5009AccountManager没有SyncAdapter?)

为了解决这个问题,我实现了一个存根SyncAdapter,它只是null从中返回IBinder onBind(Intent intent),并将相关内容添加到清单中.这解决了Android 2.1上的重启问题.

然而,它引入了另一个问题:添加帐户后,Android系统稍后会启动帐户同步.虽然没有发生错误(事实上我的SyncAdapter什么都不做,但除非通过返回null,否则无法导致错误),同步图标仍然卡在顶部的通知栏中.这导致Android同步系统保持永久唤醒锁定,防止设备休眠.

该帐户未在帐户设置屏幕中列出任何可同步组件(在"数据和同步"标题下),并且始终在帐户列表中显示"同步已关闭"同步状态(即使同步图标在通知栏).禁用帐户同步不会消除此问题.删除帐户可以解决问题.

我的猜测是我不应该返回null.我应该返回ThreadedSyncAdapter的基本实现吗?任何帮助获得帐户系统没有关联同步在2.1和2.2+上正常工作非常感谢.

Joe*_*p_H 6

因为这是我见过的与这个问题有关的唯一问题,所以这是一个晚了一年的答案.由于android系统自动同步我的自定义帐户,我也遇到了永久唤醒锁定问题.

处理此问题的最佳方法是,需要最少的代码并实际上使帐户永远不会同步,除非在代码中专门调用同步:

ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
Run Code Online (Sandbox Code Playgroud)

现在,这需要您创建帐户的那一刻调用此静态方法.第一个参数是设置此设置的帐户,第二个参数是使用的contentprovider的权限,第三个参数是设置为正数的整数启用同步,设置为0时禁用同步和设置为其他任何让它不为人知.可以在contentAuthority属性下的"sync_something.xml"中找到使用权限,该属性由SyncAdapter使用:

<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts" 
android:accountType="com.myapp.account"/> <!-- This being your own account type-->
Run Code Online (Sandbox Code Playgroud)

上面的xml文件是在AndroidManifest.xml的服务部分中指定的:

<service android:name=".DummySyncAdapterService"
        exported="true"
        android:process=":contacts">
        <intent-filter>
            <action android:name="android.content.SyncAdapter" />
        </intent-filter>
        <meta-data android:name="android.content.SyncAdapter" 
            android:resource="@xml/sync_something" /> <!--This points to your SyncAdapter XML-->
    </service>
Run Code Online (Sandbox Code Playgroud)

这是我用于在LoginActivity中创建自定义帐户的代码段:

Account account = new Account("John Doe", "com.myapp.account");
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
AccountManager am = AccountManager.get(LoginActivity.this);
boolean accountCreated = am.addAccountExplicitly(account, "Password", null);
Bundle extras = LoginActivity.this.getIntent().getExtras();
if(extras != null){
    if (accountCreated) { 
        AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
        Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, "John Doe");
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, "com.myapp.account");
        response.onResult(result);
    }
}
Run Code Online (Sandbox Code Playgroud)

其中很大一部分是当系统尝试同步服务时,它会先检查服务是否可以同步,如果设置为false则取消同步.现在您不必创建自己的数据,ContentProvider也不必ContentProvider在数据和同步下显示.但是你需要有一个AbstractThreadedSyncAdapter的存根实现,它在它的onBind方法中返回一个IBinder.最后但并非最不重要的是它使得用户无法启用同步或使用此帐户的"立即同步"按钮,除非您在应用程序中添加了功能.


Jos*_*arl 2

我解决了我自己的问题:你不能nullonBind你的服务方法返回 - 你必须IBinder返回AbstractThreadedSyncAdapter.

即使我的实现不执行任何操作,这也会在帐户设置页面的数据和同步部分添加条目,从而产生不良影响AbstractThreadedSyncAdapter;我本来希望能避免这种情况。

总而言之,为了使用 Android 中的帐户系统,您必须:

  • IntentFilter实现一个具有for的服务android.content.SyncAdapter
  • 该服务必须从其方法返回IBinder一个实现。AbstractThreadedSyncAdapteronBind
  • 这就需要您有一个在 SyncAdapter XML 文件中ContentProvider引用的(可以只是一个存根实现) 。contentAuthority
  • 这样做的缺点是您的 ContentProvider 列在帐户设置页面的数据和同步标题下。