동기화 어댑터 만들기

참고: WorkManager를 사용하는 것이 좋습니다. 를 사용하는 것이 좋습니다. 자세한 내용은 백그라운드 처리 가이드를 참조하세요.

앱의 동기화 어댑터 구성요소는 데이터를 전송하는 작업의 코드를 캡슐화합니다. 장치와 서버 간의 데이터 상호 연결입니다. Google Ads에서 제공하는 일정 및 트리거를 바탕으로 동기화 어댑터 프레임워크가 동기화 어댑터 구성요소에서 코드를 실행합니다. 광고 소재에 동기화 어댑터 구성요소를 앱에 추가하려면 다음 항목을 추가해야 합니다.

동기화 어댑터 클래스.
동기화 어댑터와 호환되는 인터페이스에서 데이터 전송 코드를 래핑하는 클래스입니다. 프레임워크입니다
바인드된 Service.
동기화 어댑터 프레임워크가 동기화 어댑터에서 코드를 실행하도록 허용하는 구성요소입니다. 클래스에 대해 자세히 알아보세요.
동기화 어댑터 XML 메타데이터 파일.
동기화 어댑터에 관한 정보가 포함된 파일입니다. 프레임워크는 이 파일을 읽고 데이터 전송을 로드하고 예약하는 방법을 알아봅니다.
앱 manifest에서 선언.
바인딩된 서비스를 선언하고 동기화 어댑터별 메타데이터를 가리키는 XML입니다.

이 학습 과정에서는 이러한 요소를 정의하는 방법을 안내합니다.

동기화 어댑터 클래스 만들기

이 단원에서는 데이터 전송 코드입니다. 클래스 생성에는 동기화 어댑터 기본 클래스 확장, 클래스에 대한 생성자 및 데이터 전송을 정의하는 메서드 구현 할 수 있습니다

기본 동기화 어댑터 클래스 확장

동기화 어댑터 구성요소를 만들려면 먼저 AbstractThreadedSyncAdapter와 생성자를 작성하는 방법을 보여줍니다. 사용 생성자를 호출하여 동기화 어댑터 구성요소가 생성될 때마다 설정 작업을 실행합니다. Activity.onCreate()를 사용하여 있습니다. 예를 들어 앱이 콘텐츠 제공자를 사용하여 데이터를 저장하는 경우 생성자를 사용합니다. ContentResolver 인스턴스를 가져옵니다. 두 번째 형태의 생성자가 parallelSyncs를 지원하기 위해 Android 플랫폼 버전 3.0에 추가되었습니다. 인수의 경우 호환성을 유지하기 위해 두 가지 형태의 생성자를 만들어야 합니다.

참고: 동기화 어댑터 프레임워크는 동기화 어댑터와 함께 작동하도록 설계되었습니다. 싱글톤 인스턴스인 구성요소를 사용합니다 동기화 어댑터 구성요소 인스턴스화에 관해 설명 이 섹션에 대한 자세한 내용은 동기화 어댑터를 프레임워크에 바인딩합니다.

다음 예는 AbstractThreadedSyncAdapter 및 그 생성자:

Kotlin

/**
 * Handle the transfer of data between a server and an
 * app, using the Android sync adapter framework.
 */
class SyncAdapter @JvmOverloads constructor(
        context: Context,
        autoInitialize: Boolean,
        /**
         * Using a default argument along with @JvmOverloads
         * generates constructor for both method signatures to maintain compatibility
         * with Android 3.0 and later platform versions
         */
        allowParallelSyncs: Boolean = false,
        /*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */
        val mContentResolver: ContentResolver = context.contentResolver
) : AbstractThreadedSyncAdapter(context, autoInitialize, allowParallelSyncs) {
    ...
}

자바

/**
 * Handle the transfer of data between a server and an
 * app, using the Android sync adapter framework.
 */
public class SyncAdapter extends AbstractThreadedSyncAdapter {
    ...
    // Global variables
    // Define a variable to contain a content resolver instance
    ContentResolver contentResolver;
    /**
     * Set up the sync adapter
     */
    public SyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
        /*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */
        contentResolver = context.getContentResolver();
    }
    ...
    /**
     * Set up the sync adapter. This form of the
     * constructor maintains compatibility with Android 3.0
     * and later platform versions
     */
    public SyncAdapter(
            Context context,
            boolean autoInitialize,
            boolean allowParallelSyncs) {
        super(context, autoInitialize, allowParallelSyncs);
        /*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */
        contentResolver = context.getContentResolver();
        ...
    }

데이터 전송 코드 추가

동기화 어댑터 구성요소에서는 데이터 전송을 자동으로 실행하지 않습니다. 대신 동기화 어댑터 프레임워크가 백그라운드에서 데이터 전송을 할 수 있습니다. 프레임워크가 준비되면 애플리케이션의 데이터를 동기화하기 위해 onPerformSync()

기본 앱 코드에서 동기화 어댑터 구성요소로 데이터를 쉽게 전송하려면 동기화 어댑터 프레임워크는 onPerformSync() 다음 인수:

계정
트리거된 이벤트와 연결된 Account 객체 동기화 어댑터입니다. 서버에서 계정을 사용하지 않는 경우 정보를 저장할 수 있습니다.
추가
동기화를 트리거한 이벤트에서 전송한 플래그가 포함된 Bundle 어댑터에 연결합니다.
권한
시스템 내 콘텐츠 제공자의 권한입니다. 앱이 다음에 액세스할 수 있어야 합니다. 이 제공업체 일반적으로 권한은 자체 앱의 콘텐츠 제공자에 상응합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.
콘텐츠 제공업체 클라이언트
ContentProviderClient: 권한 인수입니다. ContentProviderClient는 간단한 공개입니다. 인터페이스입니다. 기본 기능은 ContentResolver 콘텐츠 제공업체를 사용하여 데이터를 저장하는 경우 이 객체를 사용하여 제공자에 연결할 수 있습니다. 그렇지 않은 경우 있습니다.
동기화 결과
동기화에 정보를 전송하는 데 사용하는 SyncResult 객체 어댑터 프레임워크입니다.

다음 스니펫은 onPerformSync():

Kotlin

/*
 * Specify the code you want to run in the sync adapter. The entire
 * sync adapter runs in a background thread, so you don't have to set
 * up your own background processing.
 */
override fun onPerformSync(
        account: Account,
        extras: Bundle,
        authority: String,
        provider: ContentProviderClient,
        syncResult: SyncResult
) {
    /*
     * Put the data transfer code here.
     */
}

자바

/*
 * Specify the code you want to run in the sync adapter. The entire
 * sync adapter runs in a background thread, so you don't have to set
 * up your own background processing.
 */
@Override
public void onPerformSync(
        Account account,
        Bundle extras,
        String authority,
        ContentProviderClient provider,
        SyncResult syncResult) {
    /*
     * Put the data transfer code here.
     */
}

Kubernetes의 실제 구현은 onPerformSync()이(가) 다음에 해당하는 경우 서버 연결 프로토콜과 관련하여 몇 가지 선택사항이 있지만, 구현에서 수행해야 하는 일반적인 작업은 다음과 같습니다.

서버에 연결
데이터 전송이 시작될 때 네트워크를 사용할 수 있다고 가정할 수 있지만 동기화 어댑터 프레임워크는 서버에 자동으로 연결되지 않습니다.
데이터 다운로드 및 업로드
동기화 어댑터는 데이터 전송 작업을 자동화하지 않습니다. 앱을 다운로드하려면 콘텐츠 제공자에 저장하려면 데이터를 요청하고 다운로드하고 제공자에 삽입합니다. 마찬가지로 서버에 데이터를 보낼 때 파일, 데이터베이스 또는 제공자에서 읽고 업로드 요청을 전송합니다. 또한 애플리케이션을 사용하는 동안 발생하는 네트워크 오류를 처리해야 하며 데이터 전송이 실행 중입니다.
데이터 충돌 처리 또는 데이터의 최신 상태 확인
동기화 어댑터가 서버의 데이터와 데이터 간의 충돌을 자동으로 처리하지 않음 할 수 있습니다. 또한 서버의 데이터가 또는 그 반대의 경우도 마찬가지입니다. 그 대신 자체 알고리즘을 제공하여 처리하려고 한다고 가정해 보겠습니다.
정리
항상 서버와의 연결을 닫고 데이터 전송에 사용됩니다.

참고: 동기화 어댑터 프레임워크는 onPerformSync(), 자체 백그라운드 처리를 설정할 필요가 없습니다.

동기화 관련 작업 외에도 이를 네트워크에 추가하여 onPerformSync() 이 방법에 모든 네트워크 작업을 집중하면 사용하는 배터리의 전력을 절약할 수 있고 시작 및 중지하는 데 필요한 모든 구성 프로토콜입니다. 네트워크 액세스를 설정하는 방법에 대해 자세히 알아보려면 자세한 내용은 여러 네트워크 액세스를 설명하는 배터리 소모 없이 데이터 전송 교육 과정을 참조하세요. 데이터 전송 코드에 포함할 수 있는 작업

동기화 어댑터를 프레임워크에 바인딩

이제 데이터 전송 코드가 동기화 어댑터 구성요소에 캡슐화되었지만 프레임워크에 코드 액세스 권한을 제공해야 합니다 이렇게 하려면 동기화 어댑터에서 특수한 Android 바인더 객체를 전달하는 Service 구성요소를 추가할 수 있습니다 프레임워크는 이 바인더 객체를 사용해 onPerformSync() 메서드 및 데이터를 전달합니다

동기화 어댑터 구성요소를 서비스의 onCreate() 메서드와 함께 사용 설정합니다. 인스턴스화하고 onCreate()에 있는 구성요소의 경우 서비스가 시작될 때까지 만듭니다. 이는 프레임워크가 처음으로 데이터 전송 동기화 시도가 발생하는 경우 스레드로부터 안전한 방식으로 구성요소를 인스턴스화해야 합니다. 어댑터 프레임워크는 동기화 어댑터가 트리거에 응답하여 여러 개의 실행을 큐에 추가해서 할 수 있습니다.

예를 들어 다음 스니펫은 Service를 바인딩하고 동기화 어댑터 구성요소를 인스턴스화하며 Android 바인더 객체:

Kotlin

package com.example.android.syncadapter
/**
 * Define a Service that returns an [android.os.IBinder] for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
class SyncService : Service() {
    /*
     * Instantiate the sync adapter object.
     */
    override fun onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized(sSyncAdapterLock) {
            sSyncAdapter = sSyncAdapter ?: SyncAdapter(applicationContext, true)
        }
    }

    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    override fun onBind(intent: Intent): IBinder {
        /*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         *
         * We should never be in a position where this is called before
         * onCreate() so the exception should never be thrown
         */
        return sSyncAdapter?.syncAdapterBinder ?: throw IllegalStateException()
    }

    companion object {
        // Storage for an instance of the sync adapter
        private var sSyncAdapter: SyncAdapter? = null
        // Object to use as a thread-safe lock
        private val sSyncAdapterLock = Any()
    }
}

자바

package com.example.android.syncadapter;
/**
 * Define a Service that returns an <code><a href="/reference/android/os/IBinder.html">IBinder</a></code> for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
public class SyncService extends Service {
    // Storage for an instance of the sync adapter
    private static SyncAdapter sSyncAdapter = null;
    // Object to use as a thread-safe lock
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Instantiate the sync adapter object.
     */
    @Override
    public void onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
            }
        }
    }
    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    @Override
    public IBinder onBind(Intent intent) {
        /*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         */
        return sSyncAdapter.getSyncAdapterBinder();
    }
}

참고: 동기화 어댑터와 관련된 바인드된 서비스의 자세한 예를 보려면 샘플 앱을 확인해 보세요

프레임워크에 필요한 계정 추가

동기화 어댑터 프레임워크는 각 동기화 어댑터에 계정 유형이 있어야 합니다. 선언한 항목 섹션의 계정 유형 값을 인증자 메타데이터 파일을 추가합니다. 이제 이 계정 유형을 Android 시스템 계정 유형을 설정하려면 해당 계정 유형을 사용하는 자리표시자 계정을 추가하세요. 이를 위해 addAccountExplicitly()를 호출합니다.

메서드를 호출하기에 가장 좋은 위치는 다음과 같습니다. 앱의 onCreate() 메서드 확인할 수 있습니다. 다음 코드 스니펫에서는 이렇게 하는 방법을 보여줍니다.

Kotlin

...
// Constants
// The authority for the sync adapter's content provider
const val AUTHORITY = "com.example.android.datasync.provider"
// An account type, in the form of a domain name
const val ACCOUNT_TYPE = "example.com"
// The account name
const val ACCOUNT = "placeholderaccount"
...
class MainActivity : FragmentActivity() {

    // Instance fields
    private lateinit var mAccount: Account
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       ...
        // Create the placeholder account
        mAccount = createSyncAccount()
       ...
    }
    ...
    /**
     * Create a new placeholder account for the sync adapter
     */
    private fun createSyncAccount(): Account {
        val accountManager = getSystemService(Context.ACCOUNT_SERVICE) as AccountManager
        return Account(ACCOUNT, ACCOUNT_TYPE).also { newAccount ->
            /*
             * Add the account and account type, no password or user data
             * If successful, return the Account object, otherwise report an error.
             */
            if (accountManager.addAccountExplicitly(newAccount, null, null)) {
                /*
                 * If you don't set android:syncable="true" in
                 * in your <provider> element in the manifest,
                 * then call context.setIsSyncable(account, AUTHORITY, 1)
                 * here.
                 */
            } else {
                /*
                 * The account exists or some other error occurred. Log this, report it,
                 * or handle it internally.
                 */
            }
        }
    }
    ...
}

자바

public class MainActivity extends FragmentActivity {
    ...
    ...
    // Constants
    // The authority for the sync adapter's content provider
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // An account type, in the form of a domain name
    public static final String ACCOUNT_TYPE = "example.com";
    // The account name
    public static final String ACCOUNT = "placeholderaccount";
    // Instance fields
    Account mAccount;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Create the placeholder account
        mAccount = CreateSyncAccount(this);
        ...
    }
    ...
    /**
     * Create a new placeholder account for the sync adapter
     *
     * @param context The application context
     */
    public static Account CreateSyncAccount(Context context) {
        // Create the account type and default account
        Account newAccount = new Account(
                ACCOUNT, ACCOUNT_TYPE);
        // Get an instance of the Android account manager
        AccountManager accountManager =
                (AccountManager) context.getSystemService(
                        ACCOUNT_SERVICE);
        /*
         * Add the account and account type, no password or user data
         * If successful, return the Account object, otherwise report an error.
         */
        if (accountManager.addAccountExplicitly(newAccount, null, null)) {
            /*
             * If you don't set android:syncable="true" in
             * in your <provider> element in the manifest,
             * then call context.setIsSyncable(account, AUTHORITY, 1)
             * here.
             */
        } else {
            /*
             * The account exists or some other error occurred. Log this, report it,
             * or handle it internally.
             */
        }
    }
    ...
}

동기화 어댑터 메타데이터 파일 추가

동기화 어댑터 구성요소를 프레임워크에 플러그인하려면 구성요소를 설명하고 추가 플래그를 제공하는 메타데이터로 구성됩니다. 메타데이터는 동기화 어댑터용으로 만든 계정 유형, 콘텐츠 제공자 권한 선언 앱과 연결되고 동기화 어댑터와 관련된 시스템 사용자 인터페이스의 일부를 제어합니다. 다른 동기화 관련 플래그를 선언합니다. 이 메타데이터를 앱 프로젝트의 /res/xml/ 디렉터리에 있습니다. 파일 이름에는 제한이 없지만 일반적으로 syncadapter.xml이라고 합니다.

이 XML 파일에는 단일 XML 요소 <sync-adapter>가 포함되어 있으며 다음과 같은 속성이 포함됩니다.

android:contentAuthority
콘텐츠 제공업체의 URI 권한입니다. 스텁 콘텐츠 제공업체를 만든 경우 이전 과정 스텁 콘텐츠 제공자 만들기에서 앱을 실행했다면 속성 <ph type="x-smartling-placeholder">android:authorities</ph> <provider> 요소에 표시됩니다. 이 속성은 자세한 내용은 매니페스트에서 제공자를 선언합니다.
동기화 어댑터를 사용하여 콘텐츠 제공자에서 서버로 데이터를 전송하는 경우 값은 해당 데이터에 사용 중인 콘텐츠 URI 권한과 같아야 합니다. 이 값 또한 는 android:authorities 앱 매니페스트에 제공자를 선언하는 <provider> 요소의 속성입니다.
android:accountType
동기화 어댑터 프레임워크에 필요한 계정 유형입니다. 값이 동일해야 합니다. 인증자 메타데이터 파일을 만들 때 제공한 계정 유형 값 인증자 메타데이터 파일 추가 섹션에 설명되어 있습니다. 또한 섹션의 코드 스니펫에 상수 ACCOUNT_TYPE 프레임워크에 필요한 계정을 추가합니다.
설정 속성
android:userVisible
동기화 어댑터 계정 유형의 가시성을 설정합니다. 기본적으로 계정 유형과 관련된 계정 아이콘과 라벨이 계정 섹션에 있으므로 직접 동기화해야 합니다. 쉽게 연결할 수 있는 계정 유형이나 도메인이 없는 경우 어댑터가 표시되지 않음 하세요. 계정 유형을 보이지 않게 설정해도 사용자가 앱의 활동 중 하나에서 사용자 인터페이스로 동기화 어댑터를 제어해야 합니다.
android:supportsUploading
클라우드에 데이터를 업로드할 수 있습니다. false로 설정합니다(앱만 사용하는 경우). 데이터를 다운로드할 수 있습니다.
android:allowParallelSyncs
동기화 어댑터 구성요소의 여러 인스턴스를 동시에 실행할 수 있습니다. 앱에서 여러 사용자 계정을 지원하고 여러 계정을 허용하려는 경우 사용하세요. 여러 사용자가 동시에 데이터를 전송할 수 있습니다 이 플래그는 명령어를 실행하지 않으면 여러 데이터 전송을 수행할 수 있습니다
android:isAlwaysSyncable
언제든지 동기화 어댑터를 실행할 수 있음을 동기화 어댑터 프레임워크에 나타냅니다. 표시됩니다. 동기화 시기를 프로그래밍 방식으로 제어하려는 경우 이 플래그를 false로 설정한 다음 requestSync(): 동기화 어댑터입니다. 동기화 어댑터 실행에 관한 자세한 내용은 동기화 어댑터 실행

다음 예는 단일 자리표시자 계정을 사용하는 동기화 어댑터의 XML을 보여줍니다. 다운로드만 지원합니다.

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="com.example.android.datasync.provider"
        android:accountType="com.android.example.datasync"
        android:userVisible="false"
        android:supportsUploading="false"
        android:allowParallelSyncs="false"
        android:isAlwaysSyncable="true"/>

매니페스트에서 동기화 어댑터 선언

앱에 동기화 어댑터 구성요소를 추가한 다음에는 권한을 요청해야 합니다. 구성요소 사용과 관련이 있으며 바인드된 Service를 선언해야 합니다. 표시됩니다.

동기화 어댑터 구성 요소는 네트워크와 인터넷에 액세스할 수 있는 권한을 요청해야 합니다. 또한 앱에는 사용자가 동기화를 제어할 수 있도록 동기화 어댑터 설정을 읽고 쓸 수 있는 권한을 요청합니다. 어댑터를 앱의 다른 구성요소에서 프로그래매틱 방식으로 가져옵니다. 또한 개발자가 만든 인증자 구성요소를 앱에서 사용할 수 있도록 허용하는 특수 권한 자세한 내용은 스텁 인증자 만들기를 참조하세요.

이러한 권한을 요청하려면 다음을 앱 매니페스트에 다음 항목의 하위 요소로 추가하세요. <manifest>:

android.permission.INTERNET
데이터를 다운로드하거나 업로드할 수 있도록 동기화 어댑터 코드에서 인터넷에 액세스하도록 허용합니다. 데이터를 전송할 수 있습니다. 다음 경우 이 권한을 다시 추가할 필요가 없습니다. 이전 요청을 할 수 있습니다
android.permission.READ_SYNC_SETTINGS
앱이 현재 동기화 어댑터 설정을 읽을 수 있도록 허용합니다. 예를 들어 getIsSyncable()를 호출할 수 있습니다.
android.permission.WRITE_SYNC_SETTINGS
앱이 동기화 어댑터 설정을 제어하도록 허용합니다. 다음 작업을 하려면 이 권한이 필요합니다. addPeriodicSync()를 사용하여 주기적 동기화 어댑터 실행을 설정합니다. 이 권한은 다음을 호출하는 데 필요하지 않습니다. requestSync()입니다. 자세히 알아보려면 자세한 내용은 동기화 어댑터 실행을 참고하세요.

다음 스니펫에서는 권한을 추가하는 방법을 보여줍니다.

<manifest>
...
    <uses-permission
            android:name="android.permission.INTERNET"/>
    <uses-permission
            android:name="android.permission.READ_SYNC_SETTINGS"/>
    <uses-permission
            android:name="android.permission.WRITE_SYNC_SETTINGS"/>
    <uses-permission
            android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
...
</manifest>

마지막으로, 프레임워크에서 사용하는 바인드된 Service를 선언합니다. 동기화 어댑터와 상호작용하려면 다음 XML을 앱 매니페스트에 하위 요소로 추가합니다. /<application>:

        <service
                android:name="com.example.android.datasync.SyncService"
                android:exported="false"
                android:process=":sync">
            <intent-filter>
                <action android:name="android.content.SyncAdapter"/>
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter"
                    android:resource="@xml/syncadapter" />
        </service>

<intent-filter> 요소는 인텐트 작업으로 트리거되는 필터를 설정합니다. android.content.SyncAdapter: 동기화 어댑터를 실행하기 위해 시스템에서 전송합니다. 필터가 트리거되면 시스템은 개발자가 만든 바인드된 서비스를 시작합니다. 이 예에서는 SyncService 속성 android:exported="false" 앱과 시스템만 Service입니다. 속성 android:process=":sync" 는 이름이 전역 공유 프로세스에서 Service를 실행하도록 시스템에 지시합니다. sync입니다. 앱에 동기화 어댑터가 여러 개 있다면 이 프로세스를 공유할 수 있습니다. 오버헤드를 줄여줍니다

<meta-data> 요소는 이전에 만든 동기화 어댑터 메타데이터 XML 파일의 이름을 제공합니다. 이 android:name 속성은 이 메타데이터가 동기화 어댑터 프레임워크용임을 나타냅니다. 이 android:resource 요소는 메타데이터 파일의 이름을 지정합니다.

이제 동기화 어댑터의 모든 구성요소를 갖추었습니다. 다음 강의에서는 이벤트 또는 이벤트 발생 시 동기화 어댑터를 실행하도록 동기화 어댑터 프레임워크에 지시 규칙적인 일정