呼叫requestSync()
仅适用于系统已知的{Account,ContentAuthority}对。您的应用程序需要经过多个步骤才能告诉Android您可以使用特定种类的帐户来同步特定种类的内容。它在AndroidManifest中执行此操作。
1.通知Android您的应用程序包提供了同步
首先,必须在AndroidManifest.xml中声明您具有同步服务:
<service android:name=".sync.mySyncService" android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_myapp" />
</service>
<service>
标记的name属性是您要连接同步的类的名称。我将在稍后讨论。
将export设置为true可使它对其他组件可见(需要ContentResolver
可以调用它)。
意图过滤器使其能够捕获请求同步的意图。(这Intent
来自ContentResolver
您调用时ContentResolver.requestSync()
或相关的调度方法。)
该<meta-data>
标签将在下面讨论。
2.向Android提供用于查找SyncAdapter的服务
所以类本身...这是一个示例:
public class mySyncService extends Service {
private static mySyncAdapter mSyncAdapter = null;
public SyncService() {
super();
}
@Override
public void onCreate() {
super.onCreate();
if (mSyncAdapter == null) {
mSyncAdapter = new mySyncAdapter(getApplicationContext(), true);
}
}
@Override
public IBinder onBind(Intent arg0) {
return mSyncAdapter.getSyncAdapterBinder();
}
}
您的类必须扩展Service
或其子类之一,必须实现public IBinder onBind(Intent)
,并且必须SyncAdapterBinder
在被调用时返回a 。您需要一个type变量AbstractThreadedSyncAdapter
。如您所见,这几乎就是该课程中的所有内容。它存在的唯一原因是提供了一个服务,该服务为Android提供了一个标准接口来查询您自己的类SyncAdapter
。
3.提供一个class SyncAdapter
以实际执行同步。
mySyncAdapter是实际同步逻辑本身的存储位置。onPerformSync()
需要同步时调用其方法。我认为您已经具备了这一功能。
4.在帐户类型和内容授权机构之间建立绑定
再次回顾AndroidManifest,<meta-data>
我们服务中的那个奇怪的标签是在ContentAuthority和帐户之间建立绑定的关键部分。它在外部引用了另一个xml文件(随您喜欢,可以对其进行命名,与您的应用相关。)让我们看一下sync_myapp.xml:
<?xml version="1.0" encoding="utf-8" ?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.google"
android:userVisible="true" />
好的,这是怎么做的?它告诉Android,我们已定义的同步适配器(在<service>
包含<meta-data>
引用此文件的标记的标记的name元素中调用的类...)将使用com.google样式帐户同步联系人。
您所有的contentAuthority字符串都必须完全匹配,并与您要同步的字符串匹配-如果您要创建自己的数据库,则应为您定义的字符串,如果要同步已知的字符串,则应使用一些现有的设备字符串数据类型(如联系人或日历事件或您拥有的东西。)上面的(“ com.android.contacts”)恰好是联系人类型数据(惊讶,意外)的ContentAuthority字符串。
accountType还必须与已经输入的已知帐户类型之一匹配,或者必须与您正在创建的帐户类型匹配(这涉及创建AccountAuthenticator的子类以在您的服务器上获得身份验证。同样,“ com.google”是定义的字符串,用于标识... google.com样式的帐户凭据(同样,这并不奇怪。)
5.在给定的帐户/ ContentAuthority对上启用同步
最后,必须启用同步。您可以在控制面板的“帐户与同步”页面中执行此操作,方法是转到您的应用,然后在匹配的帐户中选中您应用旁边的复选框。另外,您可以在应用程序中的一些设置代码中完成此操作:
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
为了进行同步,必须启用您的帐户/授权对进行同步(如上),并且必须设置系统上的总体全局同步标志,并且设备必须具有网络连接性。
如果您的帐户/单位同步或全局同步被禁用,则调用RequestSync()确实会起作用-它设置一个标志,指示已请求同步,并且将在启用同步后立即执行。
此外,每mgv,ContentResolver.SYNC_EXTRAS_MANUAL
在requestSync的extras捆绑包中设置为true,即使全局同步已关闭,也会要求android强制同步(请注意此处的用户!)
最后,您可以再次使用ContentResolver函数设置定期排定的同步。
6.考虑多个账户的影响
可能有多个相同类型的帐户(在一台设备上设置了两个@ gmail.com帐户,或者两个Facebook帐户,或者两个Twitter帐户等)。您应该考虑这样做的应用程序含义。 ..如果您有两个帐户,则可能不想尝试将它们都同步到同一数据库表中。也许您需要指定一次只能激活一个,并在切换帐户时刷新表并重新同步。(通过查询存在哪些帐户的属性页)。也许您为每个帐户创建一个不同的数据库,也许创建不同的表,或者在每个表中创建一个键列。所有应用程序都是特定的,值得深思。 ContentResolver.setIsSyncable(Account account, String authority, int syncable)
在这里可能会引起您的兴趣。 setSyncAutomatically()
控制是否选中一个帐户/授权对或unchecked,而setIsSyncable()
提供了一种取消选中该行并使其变灰的方法,以便用户无法打开它。您可以将一个帐户设置为可同步,将另一个帐户设置为不同步(dsabled)。
7.注意ContentResolver.notifyChange()
一件事棘手。ContentResolver.notifyChange()
是ContentProvider
s用来通知Android本地数据库已更改的函数。这具有两个功能,首先,它将导致内容uri之后的游标进行更新,然后重新查询,使a无效并重绘ListView
,等等。这非常神奇,数据库会更改并且您会ListView
自动更新。太棒了 此外,当数据库发生更改时,Android也会为您请求同步,即使您的正常计划之外也是如此,以便使这些更改从设备中删除并尽快同步到服务器。也很棒
不过有一种情况。如果您从服务器中拉出更新,然后将更新推送到中ContentProvider
,它会尽职尽责地调用,notifyChange()
而android将运行,“哦,数据库更改,最好将它们放在服务器上!” (Doh!)写得好的ContentProviders
将进行一些测试,以查看更改是来自网络还是来自用户,syncToNetwork
如果是,则将布尔标志设置为false,以防止这种浪费的双重同步。如果您要将数据输入到中ContentProvider
,则您应该弄清楚如何使它工作-否则,当只需要一次同步时,最终将总是执行两次同步。
8.感到快乐!
一旦所有这些xml元数据都就位并启用了同步,Android将知道如何为您连接所有内容,并且同步应该开始工作。在这一点上,很多很好的事情会随处可见,就像魔术一样。请享用!