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


112

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가 동기화를 요청하는 올바른 방법입니까? 동기화 테스터 도구가 서비스에 직접 바인딩하고 start sync를 호출하는 것처럼 보이지만 동기화 아키텍처와의 통합 목적을 어기는 것 같습니다.

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

2.1 및 2.2를 실행하는 장치의 에뮬레이터에서 테스트 중입니다.


3
내 문제는 동기화 어댑터의 중단 점에 도달하지 못했다는 것입니다. 그런 다음 서비스를 디버그하려고한다는 것을 깨달았습니다. 이것이 나와 같은 다른 사람들에게 도움이되기를 바랍니다.
dangalg

2
동기화 어댑터 서비스의 중단 점이 트리거되지 않습니다. 동기화 어댑터 서비스가 별도의 프로세스에서 실행되기 때문입니다. 이것이 @danglang이 암시 한 것입니다. 이 질문도 참조하십시오 : stackoverflow.com/questions/8559458/…
Konstantin Schubert

1
제 경우 android:process=":sync"에는 동기화 서비스에서 제거 하면 디버거가 부리 지점을 밟게됩니다. onPerformSync다른 프로세스를 대신하여 메소드에서 로그 메시지를 볼 수 있었기 때문에 동기화 서비스 자체가 그 전에 작동했습니다 .
세르게이

또 다른 원인은 WiFi가 꺼져 있기 때문에 모의 데이터와 동기화하려는 경우 연결을 확인하십시오.
Allan Veloso

답변:


280

호출 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에서 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호출 될 때를 반환해야합니다 ... 유형의 변수가 필요합니다 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>태그 의 이름 요소에서 호출 된 클래스 ...)가 com.google 스타일 계정을 사용하여 연락처를 동기화 함을 알려줍니다.

모든 contentAuthority 문자열은 모두 일치해야하며 동기화중인 항목과 일치해야합니다 .-- 고유 한 데이터베이스를 생성하는 경우 정의한 문자열이거나 알려진 동기화하는 경우 기존 장치 문자열을 사용해야합니다. 데이터 유형 (예 : 연락처 또는 캘린더 이벤트 또는 가지고있는 것) 위 ( "com.android.contacts")는 연락처 유형 데이터 (놀라움, 놀라움)에 대한 ContentAuthority 문자열입니다.

accountType은 이미 입력 된 알려진 계정 유형 중 하나와 일치해야하거나 생성중인 계정 유형과 일치해야합니다 (여기에는 서버에서 인증을 얻기 위해 AccountAuthenticator의 하위 클래스를 만드는 작업이 포함됩니다 ... 기사 그 자체로 가치가 있습니다.) 다시 말하지만 "com.google"은 google.com 스타일 계정 자격 증명을 식별하는 정의 된 문자열입니다 (다시 말하지만 이것은 놀라운 일이 아닙니다.).

5. 주어진 계정 / ContentAuthority 쌍에서 동기화 활성화

마지막으로 동기화를 활성화해야합니다. 제어판의 계정 및 동기화 페이지에서 앱으로 이동하고 일치하는 계정 내에서 앱 옆에있는 확인란을 설정하여이 작업을 수행 할 수 있습니다. 또는 앱의 일부 설정 코드에서 수행 할 수 있습니다.

ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

동기화가 발생하는 경우, 계정 / 권한 쌍 (위 같은) 동기화를 활성화해야합니다 설정해야 시스템의 전반적인 글로벌 동기화 플래그 장치가 네트워크에 연결되어 있어야합니다.

계정 / 권한 동기화 또는 전역 동기화가 비활성화 된 경우 RequestSync ()를 호출하면 효과가 있습니다. 동기화가 요청 된 플래그를 설정하고 동기화가 활성화되는 즉시 수행됩니다.

또한 mgvContentResolver.SYNC_EXTRAS_MANUALrequestSync의 추가 번들에서 true로 설정 하면 전역 동기화가 꺼져 있어도 Android에 강제로 동기화하도록 요청합니다 (여기에서 사용자를 존중하십시오!).

마지막으로 ContentResolver 기능을 사용하여 정기적으로 예약 된 동기화를 설정할 수 있습니다.

6. 여러 계정의 의미 고려

동일한 유형의 계정을 두 개 이상 가질 수 있습니다 (하나의 기기에 두 개의 @ gmail.com 계정이 설정되어 있거나 두 개의 페이스 북 계정 또는 두 개의 트위터 계정 등 ...).이를 수행하는 애플리케이션의 의미를 고려해야합니다. .. 두 개의 계정이있는 경우 두 계정을 동일한 데이터베이스 테이블에 동기화하고 싶지 않을 것입니다. 한 번에 하나만 활성화되도록 지정하고 계정을 전환하면 테이블을 비우고 다시 동기화해야 할 수 있습니다. (어떤 계정이 있는지 쿼리하는 속성 페이지를 통해). 각 계정에 대해 다른 데이터베이스를 만들거나 다른 테이블을 만들거나 각 테이블의 키 열을 만들 수 있습니다. 모든 응용 프로그램은 특정하고 생각할만한 가치가 있습니다. ContentResolver.setIsSyncable(Account account, String authority, int syncable)여기에 관심이있을 수 있습니다. setSyncAutomatically()제어 계정 / 권한 쌍이되어 있는지 확인 하거나선택하지 않은 반면 setIsSyncable()해제하고 사용자가 컴퓨터를 켭 할 수 있도록 라인을 회색으로 할 수있는 방법을 제공합니다. 하나의 계정을 동기화 가능으로 설정하고 다른 하나는 동기화 불가능 (dsabled)으로 설정할 수 있습니다.

7. ContentResolver.notifyChange ()에 유의하십시오.

까다로운 한 가지. s가 로컬 데이터베이스가 변경되었음을 Android에 알리는 ContentResolver.notifyChange()데 사용하는 함수 ContentProvider입니다. 이것은 두 가지 기능을 제공합니다. 첫째, 해당 콘텐츠 uri를 따르는 커서가 업데이트되고 차례로 다시 쿼리하고 무효화하고 다시 그리는 ListView등 ... 매우 마술 적이며 데이터베이스가 변경되고 ListView자동으로 업데이트됩니다. 대박. 또한 데이터베이스가 변경되면 Android는 정상적인 일정을 벗어난 경우에도 동기화를 요청하므로 이러한 변경 사항이 장치에서 제거되고 가능한 한 빨리 서버에 동기화됩니다. 또한 굉장합니다.

하지만 하나의 엣지 케이스가 있습니다. 서버에서 가져 와서에 업데이트를 푸시 ContentProvider하면 성실하게 전화를 걸고 notifyChange()Android는 "오, 데이터베이스 변경 사항, 서버에 추가하는 것이 좋습니다!"라고합니다. (Doh!) Well-written ContentProviders은 변경 사항이 네트워크 또는 사용자로부터 왔는지 확인하기위한 몇 가지 테스트를 거치며, syncToNetwork그렇다면이 낭비적인 이중 동기화를 방지하기 위해 부울 플래그를 false로 설정합니다 . 에 데이터를 제공하는 ContentProvider경우이 작업을 수행하는 방법을 알아 내야합니다. 그렇지 않으면 하나만 필요할 때 항상 두 개의 동기화를 수행하게됩니다.

8. 행복하세요!

이 모든 XML 메타 데이터를 제자리에두고 동기화를 활성화하면 Android가 모든 것을 연결하는 방법을 알고 동기화가 작동하기 시작합니다. 이 시점에서 멋진 많은 것들이 제자리에 고정되어 마치 마법처럼 느껴질 것입니다. 즐겨!


11
ContentResolver.setSyncAutomatically (계정, AUTHORITY, true);
jcwenger 2011 년

1
문제 없습니다. 도와 드릴 수있어 기쁩니다. 다시 한 번 스타일 관점에서 "AUTHORITY"및 "myaccounttype"이 사용중인 실제 문자열 인 경우 (사이트에 복사-과거하기위한 샘플뿐만 아니라) 이름 지정 규칙을 정리해야합니다. 이러한 문자열은 모든 장치에서 고유해야하며 다른 프로그래머가 권한을 위해 일치하는 문자열로 패키지를 느리게 만들어 충돌이 발생하면 실제 문제가 발생할 수 있습니다. 건배!
jcwenger 2011 년

22
글로벌 동기화 설정이 꺼져 있어도 동기화를 요청할 수 있습니다. ContentResolver.SYNC_EXTRAS_MANUAL엑스트라 번들에 true로 설정하기 만하면 동기화가 강제됩니다. :)
mgv 2011 년

2
@kaciula : 아무것도 모르지만 장치는 동기화가 필요하다는 것을 기억하고 글로벌 동기화가 켜지 자마자 시작됩니다. 특히 "글로벌 동기화 끄기"는 중요한 상황에서 배터리를 절약하는 주요 방법 중 하나이기 때문에 사용자를이기려고해서는 안됩니다. 데이터가 동기화되지 않는 것이 정말 걱정된다면 데이터가 한동안 앉아 있었다면 사용자에게 데이터가 이동하지 않는 이유를 알려주는 팝업을 고려해보십시오. 이렇게하면 실수로 장치를 잘못 구성한 사용자를 교육하고 파워 유저가 잊어 버린 경우이를 상기시킬 수 있습니다.
jcwenger

2
addPeriodicSync ()를 사용하려는 경우에만 작동하는 것 같습니다. 나는 그것이 원래 질문의 일부가 아니라는 것을 알고 있지만 이것은 완전한 대답입니다!
android.weasel

0

setIsSyncableAccountManager setAuthToken메서드를 따라 가고있었습니다 . 그러나 setAuthToken이전 setIsSyncable에 반환 된 함수 에 도달했습니다. 주문 변경 후 모든 것이 잘 작동했습니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.