问题描述
我想实现的内容提供商同步适配器模式作为在的 - 幻灯片26.我的内容提供商合作,和我同步工作,当我从开发工具同步测试器应用程序触发它,但是当我打电话ContentResolver.requestSync(账号,权限,包)从我的ContentProvider ,我的同步永远不会触发。
I am trying to implement the Content-Provider-Sync Adapter pattern as discussed at Google IO - slide 26. My content provider is working, and my sync works when I trigger it from the Dev Tools Sync Tester application, however when I call ContentResolver.requestSync(account, authority, bundle) from my ContentProvider, my sync is never triggered.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
编辑 - 添加清单片段我的清单XML包含:
Edit -- added manifest snippetMy manifest xml contains:
<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>
- 修改
--Edit
我和我的同步服务相关syncadapter.xml包括:
My syncadapter.xml associated with my sync service contains:
<?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"
/>
不知道还有什么其他code将是有益的。传递给requestSync的账户是myaccounttype,并通过呼叫管理局符合我SYC适配器XML。
Not sure what other code would be useful. The account passed to requestSync is of "myaccounttype" and the AUTHORITY passed to the call matches my syc adapter xml.
时ContentResolver.requestSync要求同步的正确方法?它看起来像同步测试工具,直接绑定到服务,并呼吁启动同步,但好像它违背了与同步架构相结合的目的。
Is ContentResolver.requestSync the correct way to request a sync? It looks like the sync tester tool binds directly to the service and calls start sync, but that seems like it defeats the purpose of integrating with the sync architecture.
如果是请求同步,那么正确的方式为什么会同步测试工作,但不是我的电话给ContentResolver.requestSync?有什么我需要传递的包?
If that is the correct way to request a sync then why would the sync tester work, but not my call to ContentResolver.requestSync? Is there something I need to pass in the bundle?
我上运行2.1和2.2的设备测试中的模拟器。
I am testing in the emulator on devices running 2.1 and 2.2.
在此先感谢您的帮助,
--Ben
Thanks in advance for your help,
--Ben
推荐答案
RequestSync()只能在一个(帐户,ContentAuthority}对已知的系统,你的应用程序需要经过多个步骤,告诉的Android,你是能够同步特定类型的使用特定类型的账户的内容。它这样做是在AndroidManifest。
RequestSync() will only work on a (Account, ContentAuthority} pair that is known to the system. Your app needs to go through a number of steps to tell Android that you are capable of synchronizing a specific kind of content using a specific kind of account. It does this in the AndroidManifest.
1。通知Android,你的应用程序包提供同步
首先,在AndroidManifest.xml中,你必须声明你有一个同步服务:
First off, in AndroidManifest.xml, you have to declare that you have a Sync Service:
<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>
name是类的名字来连接同步...我会跟在第二。
name is the name of your class to connect up sync... I'll talk to that in a second.
导出使得它能够被其他组件(必须的,从而ContentResolver的可以调用它)。
exported makes it visible to other components (needed so ContentResolver can call it).
的意图过滤器让它捕获一个意图,要求同步。 (此意向来自ContentResolver的,当你打电话给你的RequestSync()函数。)
The intent filter lets it catch an intent requesting sync. (This intent comes from ContentResolver when you call your RequestSync() function.)
2。提供Android的用来寻找你的SyncAdapter服务
因此类本身......这里有一个例子:
So the class itself... Here's an example:
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();
}
}
您的类必须扩展服务。您的类必须存储类型AbstractThreadedSyncAdapter的成员变量,必须实施公开的IBinder onBind(意向)
,而且必须返回时,这就是所谓的SyncAdapterBinder ......因此,大家可以看到,这是pretty的每样东西在那类。它的唯一原因是,提供一种服务,即提供了Android的查询类,以你的SyncAdapter本身是一个标准的接口。
Your class must extend Service. Your class must store a member variable of type AbstractThreadedSyncAdapter, must implement public IBinder onBind(Intent)
, and must return a SyncAdapterBinder when that's called... So as you can see, that's pretty much everything in that class. The only reason it's there is to provide a Service, that offers a standard interface for Android to query your class as to what your SyncAdapter itself is.
3。提供一个类SyncAdapter
实际执行同步。
3. Provide a class SyncAdapter
to actually perform the sync.
mySyncAdapter是真正的同步逻辑本身被存储。它被调用( onPerformSync()
被调用),当它的时间同步。我想你已经有这个到位。
mySyncAdapter is where the real sync logic itself is stored. It gets called (onPerformSync()
gets called) when it's time to sync. I figure you already have this in place.
4。建立帐户类型和内容授权之间的绑定
回来看着AndroidManifest,在我们的服务奇怪的元数据标签是建立ContentAuthority和帐户之间的结合的关键部分。它外部引用了另一个XML文件(叫它任何你喜欢的,有关你的应用程序的东西。)让我们来看看sync_myapp.xml:
Looking back again at AndroidManifest, that strange meta-data tag in our service is the key piece that establishes the binding between a ContentAuthority and an account. It externally references another xml file (call it whatever you like, something relevant to your app.) Let's look at 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同步适配器我们定义(也被称为出的name元素的类&LT;服务&GT;
标记包含&LT;元&GT;
标记包含这个文件......)将使用com.google风格的账户同步联系人
Okay, so what does this do? It tells Android that the sync adapter we've defined (the class that was called out in the name element of the <service>
tag that includes the <metadata>
tag that includes this file...) will sync contacts using a com.google style account.
您所有的contentAuthority字符串必须全部匹配,并匹配与你同步的东西 - 这应该是你定义一个字符串,如果您要创建自己的数据库,或者如果你'你应该使用一些现有的设备字符串重新同步已知的数据类型(如联系人或日历事件,或你有什么。)上述(com.android.contacts)恰好是ContentAuthority串联系人类型数据(惊奇,惊奇)。
All your contentAuthority strings have to all match, and match with what you're syncing -- This should be a string you define, if you're creating your own database, or you should use some existing device strings if you're syncing known data types (like contacts or calendar events or what have you.) The above ("com.android.contacts") happens to be the ContentAuthority string for contacts type data (surprise, surprise.)
accountType也有相匹配那些已经进入那些已知的帐户类型之一,或有匹配一个你创建(这包括创建AccountAuthenticator的一个子类来获得身份验证您的服务器上... ...的文章的价值本身)。再次,com.google的定义字符串,标识...... google.com风格帐户凭据(同样,这不应该是一个惊喜。)
accountType also has to match one of those known account types that are already entered, or it has to match one you're creating (This involves creating a subclass of AccountAuthenticator to get auth on your server... An article worth itself.) Again, "com.google" is the defined string identifying... google.com style account credentials (again, this should not be a surprise.)
5。启用同步在一个给定的帐户/ ContentAuthority对
最后,同步已经被激活。您可以在帐户与做到这一点;在控制面板同步页转到你的应用程序和设置旁边的复选框匹配的帐户内的应用程序。或者,你可以做一些设置code。在您的应用程序:
Finally, sync has to be enabled. You can do this in the Accounts & Sync page in the control panel by going to your app and setting the checkbox next to your app within the matching account. Alternately, you can do it in some setup code in your app:
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
有关发生同步,您的帐户/权限对必须启用同步(如上)的和的系统上的整个全球同步标志必须设置的和的该设备必须具有网络连接。
For sync to occur, your account/authority pair must be enabled to sync (like above) and the overall global sync flag on the system must be set, and the device must have network connectivity.
如果您的帐户/权限同步或全球同步被禁用,呼吁RequestSync()确实有效果 - 它设置的同步已请求标志,并会尽快同步启用执行。
If your account/authority sync or the global sync are disabled, calling RequestSync() does have an effect -- It sets a flag that sync has been requested, and will be performed as soon as sync is enabled.
此外,每货车,设置 ContentResolver.SYNC_EXTRAS_MANUAL
为true您requestSync的额外软件包会问机器人强制同步,即使全球同步关闭(尊重你的用户在这里!)
Also, per mgv, setting ContentResolver.SYNC_EXTRAS_MANUAL
to true in the extras bundle of your requestSync will ask android to force a sync even if global sync is off (be respectful of your user here!)
最后,你可以设置一个周期性定时同步,再次ContentResolver的功能。
Finally, you can setup a periodic scheduled sync, again with ContentResolver functions.
6。考虑多个帐户的影响
有可能有一个以上的账户同类型的(两个@ gmail.com帐户设置一个设备或两个Facebook账号,或两个Twitter账户,等等。)您应该考虑的应用程序的影响这样做......如果你有两个帐户,你可能不会想尝试他们两个同步到同一个数据库表。也许你需要指定唯一一个可以同时处于活动状态,并且刷新表,如果你切换帐户重新同步。 (通过属性页面,查询哪些账户是present)。也许你创建一个不同的数据库,为每个帐户,也许不同的表,每个表也许键列。具体的,值得一些思考的所有应用程序。 ContentResolver.setIsSyncable(客户账户,串权威诠释可同步)
可能是这里的利益。 setSyncAutomatically()控制的帐户/机构对是否检查或选中的,而setIsSyncable()提供了一种方法来取消和灰色,线,使用户无法打开它在。你可以设置一个帐户可同步和其他没有可同步(dsabled)。
It is possible to have more than one account of the same type (two @gmail.com accounts set up on one device or two facebook accounts, or two twitter accounts, etc...) You should consider the application implications of doing that... If you have two accounts, you probably don't want to try to sync both of them into the same database tables. Maybe you need to specify that only one can be active at a time, and flush the tables and resync if you switch accounts. (through a property page that queries what accounts are present). Maybe you create a different database for each account, maybe different tables, maybe a key column in each table. All application specific and worthy of some thought. ContentResolver.setIsSyncable(Account account, String authority, int syncable)
might be of interest here. setSyncAutomatically() controls whether an account/authority pair is checked or unchecked, whereas setIsSyncable() provides a way to uncheck and grey out the line so the user can't turn it on. You might set one account Syncable and the other not Syncable (dsabled).
7。请注意ContentResolver.notifyChange的()
一个棘手的事情。 ContentResolver.notifyChange()是一种用于ContentProviders通知机器人本地数据库已经改变的功能。这有两个功能,一是会造成以下的contenturi更新游标,进而重新查询和无效并重新绘制一个ListView,等等...这是非常神奇的,对数据库的修改和您的ListView只是自动更新。真棒。此外,当数据库发生改变,Android将要求同步你的,即使不在你的正常的作息时间,使这些变化得到带下设备并同步到服务器尽可能快地。此外真棒。
One tricky thing. ContentResolver.notifyChange() is a function used by ContentProviders to notify Android that the local database has been changed. This serves two functions, first, it will cause cursors following that contenturi to update, and in turn requery and invalidate and redraw a ListView, etc... It's very magical, the database changes and your ListView just updates automatically. Awesome. Also, when the database changes, Android will request Sync for you, even outside your normal schedule, so that those changes get taken off the device and synced to the server as rapidly as possible. Also awesome.
还有一个边缘的情况下,虽然。如果从服务器上拉,推的更新到ContentProvider的,它会忠实地调用有NotifyChange()和android会去,哦,数据库的变化,更好地把他们的服务器上! (卫生署!)写得ContentProviders会有一些测试,看是否改变从网络或从用户来了,将设置布尔syncToNetwork标志,假的,如果是这样,以prevent这种浪费的双同步。如果你将数据输入ContentProvider的,则您有义务找出如何得到这个工作 - 否则你会最终总是执行两种同步时,只需要一个
There's one edge case though. If you pull from the server, and push an update into the ContentProvider, it will dutifully call notifyChange() and android will go, "Oh, database changes, better put them on the server!" (Doh!) Well written ContentProviders will have some tests to see if the changes came from the network or from the user, and will set the boolean syncToNetwork flag false if so, to prevent this wasteful double-sync. If you're feeding data into a ContentProvider, it behooves you to figure out how to get this working -- Otherwise you'll end up always performing two syncs when only one is needed.
8。感到幸福!
一旦你拥有了这一切的XML元数据的地方,并同步启用,Android将知道如何连接一切为您,和同步应该开始工作。在这一点上,很多东西都是不错的只是点击进入的地方,会觉得很像魔术。尽情享受吧!
Once you have all this xml metadata in place, and sync enabled, Android will know how to connect everything up for you, and sync should start working. At this point, a lot of things that are nice will just click into place and it will feel a lot like magic. Enjoy!
这篇关于为什么ContentResolver.requestSync不会触发同步?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!