সিঙ্ক অ্যাডাপ্টার তৈরি করা

মনে রাখবেন: ব্যাকগ্রাউন্ড প্রসেসিংয়ের বেশিরভাগ ব্যবহারের ক্ষেত্রে আমরা WorkManager ব্যবহার করার সাজেশন দিই। কোন সমাধান আপনার জন্য সবচেয়ে ভালো কাজ করে তা জানতে ব্যাকগ্রাউন্ড প্রসেসিং গাইড দেখুন।

আপনার অ্যাপের সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট, ডিভাইস ও সার্ভারের মধ্যে ডেটা ট্রান্সফার করার টাস্কের কোড এনক্যাপসুলেট করে। আপনার অ্যাপে দেওয়া শিডিউল ও ট্রিগারের উপর ভিত্তি করে, সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ক সিঙ্ক অ্যাডাপ্টার কম্পোনেন্টে কোড রান করে। আপনার অ্যাপে সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট যোগ করতে, আপনাকে নিম্নলিখিত অংশগুলি যোগ করতে হবে:

সিঙ্ক অ্যাডাপ্টার ক্লাস।
একটি ক্লাস যা সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্কের সাথে মানানসই ইন্টারফেসে আপনার ডেটা ট্রান্সফার কোডকে র‍্যাপ করে।
Service বাউন্ড।
একটি কম্পোনেন্ট যা সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ককে আপনার সিঙ্ক অ্যাডাপ্টার ক্লাসে কোড রান করার অনুমতি দেয়।
সিঙ্ক অ্যাডাপ্টার XML মেটাডেটা ফাইল।
আপনার সিঙ্ক অ্যাডাপ্টার সম্পর্কিত তথ্য সহ একটি ফাইল। আপনার ডেটা ট্রান্সফার কীভাবে লোড ও শিডিউল করতে হবে তা খুঁজে বের করতে ফ্রেমওয়ার্ক এই ফাইলটি পড়ে।
অ্যাপ ম্যানিফেস্টে ঘোষণা।
XML যা বাউন্ড পরিষেবা ঘোষণা করে এবং সিঙ্ক অ্যাডাপ্টার-নির্দিষ্ট মেটাডেটা নির্দেশ করে।

এইসব এলিমেন্ট কীভাবে সংজ্ঞায়িত করতে হয় তা এই টিউটোরিয়াল থেকে জানতে পারবেন।

সিঙ্ক অ্যাডাপ্টার ক্লাস তৈরি করা

এই পাঠের এই অংশে আপনি শিখবেন কীভাবে সিঙ্ক অ্যাডাপ্টার ক্লাস তৈরি করতে হয় যা ডেটা ট্রান্সফার কোডকে এনক্যাপসুলেট করে। ক্লাস তৈরি করার মধ্যে রয়েছে সিঙ্ক অ্যাডাপ্টার মূল ক্লাস এক্সটেন্ড করা, ক্লাসের জন্য কনস্ট্রাক্টর সংজ্ঞায়িত করা এবং ডেটা ট্রান্সফার টাস্ক সংজ্ঞায়িত করার পদ্ধতি প্রয়োগ করা।

বেস সিঙ্ক অ্যাডাপ্টার ক্লাস এক্সটেন্ড করা

সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট তৈরি করতে, AbstractThreadedSyncAdapter এক্সটেন্ড করে এবং এর কনস্ট্রাক্টর লিখে শুরু করুন। প্রতিবার আপনার সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট স্ক্র্যাচ থেকে তৈরি করার সময় সেটআপ টাস্ক রান করতে কনস্ট্রাক্টর ব্যবহার করুন, ঠিক যেমন আপনি একটি অ্যাক্টিভিটি সেট আপ করতে Activity.onCreate() ব্যবহার করেন। যেমন, আপনার অ্যাপ ডেটা স্টোর করার জন্য কন্টেন্ট প্রোভাইডার ব্যবহার করলে, ContentResolver ইনস্ট্যান্স পেতে কনস্ট্রাক্টর ব্যবহার করুন। Android প্ল্যাটফর্ম ভার্সন ৩.০-এ parallelSyncs আর্গুমেন্টকে সাপোর্ট করার জন্য কনস্ট্রাক্টরের দ্বিতীয় ফর্ম যোগ করা হয়েছে, তাই কম্প্যাটিবিলিটি বজায় রাখতে আপনাকে কনস্ট্রাক্টরের দুটি ফর্ম তৈরি করতে হবে।

মনে রাখবেন: সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ক এমনভাবে ডিজাইন করা হয়েছে যাতে সিঙ্ক অ্যাডাপ্টার কম্পোনেন্টের সাথে কাজ করতে পারে যা সিঙ্গলটন ইনস্ট্যান্স। সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট ইনস্ট্যান্টিয়েট করার বিষয়টি ফ্রেমওয়ার্কে সিঙ্ক অ্যাডাপ্টার বাইন্ড করা বিভাগে আরও বিস্তারিতভাবে আলোচনা করা হয়েছে।

নিম্নলিখিত উদাহরণ থেকে আপনি জানতে পারবেন কীভাবে 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.
     */
}

onPerformSync()-এর আসল প্রয়োগ আপনার অ্যাপের ডেটা সিঙ্ক করার প্রয়োজনীয়তা এবং সার্ভার কানেকশন প্রোটোকলের উপর নির্ভর করে, তবে আপনার প্রয়োগের ক্ষেত্রে কিছু সাধারণ টাস্ক সম্পূর্ণ করতে হবে:

সার্ভারে কানেক্ট করা
যদিও আপনি ধরে নিতে পারেন যে আপনার ডেটা ট্রান্সফার শুরু হওয়ার সময় নেটওয়ার্ক উপলভ্য থাকে, সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ক অটোমেটিক কোনও সার্ভারের সাথে কানেক্ট করে না।
ডেটা ডাউনলোড ও আপলোড করা
সিঙ্ক অ্যাডাপ্টার কোনও ডেটা ট্রান্সফার টাস্ক অটোমেট করে না। আপনি যদি কোনও সার্ভার থেকে ডেটা ডাউনলোড করে কন্টেন্ট প্রোভাইডারে স্টোর করতে চান, তাহলে আপনাকে সেই কোড দিতে হবে যা ডেটার জন্য অনুরোধ করে, সেটি ডাউনলোড করে এবং প্রোভাইডারে যোগ করে। একইভাবে, আপনি যদি কোনও সার্ভারে ডেটা পাঠাতে চান, তাহলে আপনাকে কোনও ফাইল, ডেটাবেস বা পরিষেবা প্রদানকারীর থেকে এটি পড়তে হবে এবং প্রয়োজনীয় আপলোড অনুরোধ পাঠাতে হবে। ডেটা ট্রান্সফার চলাকালীন নেটওয়ার্কের সমস্যা হলে, আপনাকে সেটিও ম্যানেজ করতে হবে।
ডেটা সংক্রান্ত সমস্যা ম্যানেজ করা বা ডেটা কতটা আপ-টু-ডেট তা নির্ধারণ করা
সার্ভারের ডেটা এবং ডিভাইসের ডেটার মধ্যে কোনও বিরোধ দেখা দিলে, সিঙ্ক অ্যাডাপ্টার অটোমেটিক তা সমাধান করে না। এছাড়াও, সার্ভারে থাকা ডেটা ডিভাইসে থাকা ডেটার চেয়ে নতুন কিনা অথবা এর উল্টোটা, তা এটি অটোমেটিক শনাক্ত করে না। পরিবর্তে, এই পরিস্থিতি সামলানোর জন্য আপনাকে নিজের অ্যালগরিদম প্রদান করতে হবে।
ক্লিন-আপ করুন।
ডেটা ট্রান্সফার করার পরে, সার্ভারের সাথে কানেকশন সবসময় বন্ধ করে দিন এবং টেম্প ফাইল ও ক্যাশে মুছে দিন।

মনে রাখবেন: সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ক onPerformSync() ব্যাকগ্রাউন্ড থ্রেডে রান করে, তাই আপনাকে নিজের ব্যাকগ্রাউন্ড প্রসেসিং সেট-আপ করতে হয় না।

সিঙ্ক-সম্পর্কিত টাস্ক ছাড়াও, আপনার নেটওয়ার্ক-সম্পর্কিত নিয়মিত টাস্ক একত্রিত করে onPerformSync()-এ যোগ করার চেষ্টা করা উচিত। এই পদ্ধতিতে আপনার সব নেটওয়ার্ক টাস্ক একত্রিত করে, আপনি নেটওয়ার্ক ইন্টারফেস চালু ও বন্ধ করার জন্য প্রয়োজনীয় ব্যাটারি পাওয়ার সাশ্রয় করেন। নেটওয়ার্ক অ্যাক্সেস আরও দক্ষ করে তোলার ব্যাপারে আরও জানতে, ব্যাটারি ড্রেন না করে ডেটা ট্রান্সফার করা ট্রেনিং ক্লাস দেখুন, যেখানে নেটওয়ার্ক অ্যাক্সেস সংক্রান্ত বিভিন্ন টাস্কের ব্যাপারে বর্ণনা করা হয়েছে, যেগুলি আপনি ডেটা ট্রান্সফার কোডে অন্তর্ভুক্ত করতে পারবেন।

ফ্রেমওয়ার্কের সাথে সিঙ্ক অ্যাডাপ্টার বাইন্ড করুন

আপনার ডেটা ট্রান্সফার কোড এখন সিঙ্ক অ্যাডাপ্টার কম্পোনেন্টে এনক্যাপসুলেট করা আছে, তবে আপনাকে ফ্রেমওয়ার্ককে আপনার কোড অ্যাক্সেস করার অনুমতি দিতে হবে। এটি করতে, আপনাকে একটি বাউন্ড Service তৈরি করতে হবে যা সিঙ্ক অ্যাডাপ্টার কম্পোনেন্ট থেকে ফ্রেমওয়ার্কে একটি বিশেষ Android বাইন্ডার অবজেক্ট পাস করে। এই বাইন্ডার অবজেক্টের মাধ্যমে, ফ্রেমওয়ার্ক 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();
    }
}

মনে রাখবেন: সিঙ্ক অ্যাডাপ্টারের জন্য বাউন্ড পরিষেবার আরও বিস্তারিত উদাহরণ দেখতে, স্যাম্পেল অ্যাপ দেখুন।

ফ্রেমওয়ার্কের জন্য প্রয়োজনীয় অ্যাকাউন্ট যোগ করুন

সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্কের জন্য প্রতিটি সিঙ্ক অ্যাডাপ্টারের অ্যাকাউন্টের ধরন থাকতে হবে। আপনি Authenticator মেটাডেটা ফাইল যোগ করুন বিভাগে অ্যাকাউন্টের ধরন সংক্রান্ত ভ্যালু ঘোষণা করেছেন। এখন আপনাকে 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/ ডিরেক্টরিতে স্টোর করা একটি বিশেষ XML ফাইলে এই মেটাডেটা ঘোষণা করুন। আপনি ফাইলটির যেকোনও নাম দিতে পারেন, যদিও এটিকে সাধারণত syncadapter.xml বলা হয়।

এই XML ফাইলে একটিই XML এলিমেন্ট <sync-adapter> আছে, যার মধ্যে নিম্নলিখিত অ্যাট্রিবিউট আছে:

android:contentAuthority
আপনার কন্টেন্ট প্রোভাইডারের জন্য URI অথরিটি। আপনি যদি আগের পাঠে আপনার অ্যাপের জন্য একটি স্টাব কন্টেন্ট প্রোভাইডার তৈরি করে থাকেন একটি স্টাব কন্টেন্ট প্রোভাইডার তৈরি করা, আপনি যে মানটি নির্দিষ্ট করেছেন সেটি ব্যবহার করুন অ্যাট্রিবিউট android:authorities আপনার অ্যাপ ম্যানিফেস্টে যোগ করা <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 ব্যবহার করে তা ঘোষণা করতে, আপনার অ্যাপ ম্যানিফেস্টে <application>-এর চাইল্ড এলিমেন্ট হিসেবে নিম্নলিখিত XML যোগ করুন:

        <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 এলিমেন্ট মেটাডেটা ফাইলের নাম নির্দিষ্ট করে।

আপনার সিঙ্ক অ্যাডাপ্টারের জন্য এখন আপনার কাছে সব কম্পোনেন্ট আছে। পরবর্তী পাঠে আপনি জানতে পারবেন কীভাবে সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্ককে আপনার সিঙ্ক অ্যাডাপ্টার চালাতে বলবেন, কোনও ইভেন্টের উত্তরে অথবা নিয়মিত শিডিউলে।