gpt4 book ai didi

android - 为什么 ContentResolver.requestSync 不触发同步?

转载 作者:行者123 更新时间:2023-12-01 18:42:58 26 4
gpt4 key购买 nike

我正在尝试实现在 Google IO 中讨论的 Content-Provider-Sync Adapter 模式。 - 幻灯片 26。我的内容提供程序正在工作,当我从 Dev Tools Sync Tester 应用程序触发它时,我的同步工作,但是当我从我的 ContentProvider 调用 ContentResolver.requestSync(account, authority, bundle) 时,我的同步从未被触发。

ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());

编辑 - 添加 list fragment
我的 list xml 包含:
<service
android:name=".sync.SyncService"
android:exported="true">
<intent-filter>
<action
android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>

--编辑

我的同步服务相关联的 syncadapter.xml 包含:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="AUTHORITY"
android:accountType="myaccounttype"
android:supportsUploading="true"
/>

不知道还有哪些其他代码会有用。传递给 requestSync 的帐户是“myaccounttype”,传递给调用的 AUTHORITY 与我的 syc 适配器 xml 匹配。

ContentResolver.requestSync 是请求同步的正确方法吗?看起来同步测试器工具直接绑定(bind)到服务并调用开始同步,但这似乎违背了与同步架构集成的目的。

如果这是请求同步的正确方法,那么为什么同步测试器会工作,而不是我对 ContentResolver.requestSync 的调用?我需要在 bundle 中传递什么吗?

我正在运行 2.1 和 2.2 的设备上的模拟器中进行测试。

最佳答案

调用 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属性tag 是你用来连接同步的类的名称...我稍后会谈到这个。

设置导出的 true 使其对其他组件可见(需要 ContentResolver 才能调用它)。

Intent 过滤器让它捕获请求同步的 Intent 。 (这个 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();
}
}

您的类(class)必须扩展 Service或其子类之一,必须实现 public IBinder onBind(Intent) ,并且必须返回 SyncAdapterBinder当它被调用时...你需要一个 AbstractThreadedSyncAdapter 类型的变量.如您所见,这几乎是该类中的所有内容。它存在的唯一原因是提供一个服务,该服务为 Android 提供了一个标准接口(interface)来查询您的类,以了解您的 SyncAdapter本身就是。

3.提供class SyncAdapter实际执行同步。

mySyncAdapter 是存储真正同步逻辑本身的地方。它的 onPerformSync()方法在需要同步时被调用。我想你已经有了这个。

4.建立Account-type和Content Authority之间的绑定(bind)

再回头看AndroidManifest,那个奇怪的 <meta-data>我们服务中的标签是在 ContentAuthority 和帐户之间建立绑定(bind)的关键部分。它从外部引用了另一个 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> 标签的 name 元素中调用的类,其中包括引用此文件的 <meta-data> 标签...)将使用 com 同步联系人。谷歌风格帐户。

您所有的 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()控制是否选中或取消选中帐户/权限对,而 setIsSyncable()提供了一种取消选中和灰显该行的方法,因此用户无法打开它。您可以将一个帐户设置为可同步,而将另一个设置为不可同步 (dsabled)。

7. 注意 ContentResolver.notifyChange()

一件棘手的事情。 ContentResolver.notifyChange()ContentProvider 使用的函数s 通知 Android 本地数据库已更改。这有两个作用,首先,它会导致跟随该内容 uri 的游标更新,然后重新查询和无效并重绘 ListView等等...很神奇,数据库变了,你的 ListView只是自动更新。太棒了。此外,当数据库更改时,Android 会为您请求同步,即使在您的正常计划之外,以便这些更改从设备上移除并尽快同步到服务器。也很棒。

不过有一个边缘情况。如果您从服务器拉取,并将更新推送到 ContentProvider ,它将尽职尽责地拨打 notifyChange() android 会说:“哦,数据库更改了,最好将它们放在服务器上!” (Doh!)写得很好 ContentProviders将进行一些测试以查看更改是来自网络还是来自用户,并将设置 bool 值 syncToNetwork如果是这样,则标记为 false,以防止这种浪费的双同步。如果您将数据输入 ContentProvider ,你有必要弄清楚如何让这个工作 - 否则你最终会在只需要一个同步时执行两个同步。

8. 心情愉快!

一旦您准备好所有这些 xml 元数据并启用同步,Android 将知道如何为您连接所有内容,并且同步应该开始工作。在这一点上,很多很好的东西会点击到位,感觉很像魔术。享受!

关于android - 为什么 ContentResolver.requestSync 不触发同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5253858/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com