IT박스

ContentResolver.requestSync가 동기화를 트리거하지 않는 이유는 무엇입니까?

itboxs 2020. 7. 28. 08:17
반응형

ContentResolver.requestSync가 동기화를 트리거하지 않는 이유는 무엇입니까?


Google IO- 슬라이드 26 에서 설명한대로 Content-Provider-Sync Adapter 패턴을 구현하려고합니다 . 컨텐츠 제공자가 작동하고 있으며 Dev Tools Sync Tester 애플리케이션에서 트리거 할 때 ContentResolver를 호출하면 동기화가 작동합니다. 내 ContentProvider의 requestSync (계정, 권한, 번들), 동기화가 트리거되지 않습니다.

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

편집-매니페스트 스 니펫 추가 내 매니페스트 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가 동기화를 요청하는 올바른 방법입니까? 동기화 테스터 도구가 서비스에 직접 바인딩되고 동기화 시작을 호출하는 것처럼 보이지만 동기화 아키텍처와 통합하려는 목적을 상실한 것처럼 보입니다.

이것이 동기화를 요청하는 올바른 방법이라면 동기화 테스터가 작동하지만 ContentResolver.requestSync에 대한 호출이 작동하지 않는 이유는 무엇입니까? 번들에 전달해야 할 것이 있습니까?

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>태그 의 이름 속성은 동기화를 연결하는 클래스의 이름입니다. 잠시 후에 설명하겠습니다.

내 보낸 true를 설정하면 다른 구성 요소에 표시됩니다 (필요한 경우 ContentResolver호출 가능).

인 텐트 필터를 사용하면 인 텐트 요청 동기화를 포착 할 수 있습니다. (이것은 전화 또는 관련 예약 방법 Intent에서 나옵니다 .)ContentResolverContentResolver.requestSync()

<meta-data>태그는 아래에서 논의 될 것이다.

2. SyncAdapter를 찾는 데 사용되는 서비스를 Android에 제공하십시오.

클래스 자체는 다음과 같습니다. 예를 들면 다음과 같습니다.

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();
    }
}

Your class must extend Service or one of its subclasses, must implement public IBinder onBind(Intent), and must return a SyncAdapterBinder when that's called... You need a variable of type AbstractThreadedSyncAdapter. 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. Provide a class SyncAdapter to actually perform the sync.

mySyncAdapter is where the real sync logic itself is stored. Its onPerformSync() method gets called when it's time to sync. I figure you already have this in place.

4. Establish a binding between an Account-type and a Content Authority

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" /> 

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 <meta-data> tag that references this file...) will sync contacts using a com.google style account.

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 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... Worth an article, itself.) Again, "com.google" is the defined string identifying... google.com style account credentials (again, this should not be a surprise.)

5. Enable Sync on a given Account / ContentAuthority pair

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.

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.

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!)

Finally, you can setup a periodic scheduled sync, again with ContentResolver functions.

6. Consider implications of multiple accounts

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. Be aware of ContentResolver.notifyChange()

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 content uri 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.

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. Feel happy!

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!


I was caling setIsSyncable after AccountManager setAuthToken method. But setAuthToken returned function before setIsSyncable was reached. After order changes everything worked fine!

참고URL : https://stackoverflow.com/questions/5253858/why-does-contentresolver-requestsync-not-trigger-a-sync

반응형