Chạy bộ điều hợp đồng bộ hoá

Lưu ý: Bạn nên sử dụng WorkManager làm giải pháp đề xuất cho hầu hết các trường hợp sử dụng xử lý nền. Vui lòng tham khảo hướng dẫn xử lý nền để tìm hiểu giải pháp nào phù hợp nhất với bạn.

Trong các bài học trước trong lớp học này, bạn đã tìm hiểu cách tạo thành phần bộ điều hợp đồng bộ hoá đóng gói mã chuyển dữ liệu, cũng như cách thêm các thành phần bổ sung cho phép bạn cắm bộ điều hợp đồng bộ hoá vào hệ thống. Giờ đây, bạn đã có mọi thứ cần thiết để cài đặt một ứng dụng bao gồm bộ điều hợp đồng bộ hoá, nhưng không có mã nào trong số mã bạn thấy chạy bộ điều hợp đồng bộ hoá đó.

Bạn nên cố gắng chạy bộ điều hợp đồng bộ hoá dựa trên lịch biểu hoặc do kết quả gián tiếp của một số sự kiện. Ví dụ: bạn có thể muốn bộ điều hợp đồng bộ hoá chạy theo một lịch biểu định kỳ, sau một khoảng thời gian nhất định hoặc tại một thời điểm cụ thể trong ngày. Bạn cũng nên chạy bộ điều hợp đồng bộ hoá khi có thay đổi đối với dữ liệu được lưu trữ trên thiết bị. Bạn nên tránh chạy bộ điều hợp đồng bộ hoá dưới dạng kết quả trực tiếp của hành động của người dùng, vì làm như vậy sẽ không được hưởng toàn bộ lợi ích từ khả năng lên lịch của khung bộ điều hợp đồng bộ hoá. Ví dụ: bạn nên tránh cung cấp nút làm mới trong giao diện người dùng.

Bạn có các lựa chọn sau để chạy bộ điều hợp đồng bộ hoá:

Khi dữ liệu máy chủ thay đổi
Chạy bộ điều hợp đồng bộ hoá để phản hồi thông báo từ máy chủ, cho biết rằng dữ liệu dựa trên máy chủ đã thay đổi. Tuỳ chọn này cho phép bạn làm mới dữ liệu từ máy chủ sang thiết bị mà không làm giảm hiệu suất hoặc lãng phí thời lượng pin bằng cách thăm dò máy chủ.
Khi dữ liệu thiết bị thay đổi
Chạy bộ điều hợp đồng bộ hoá khi dữ liệu trên thiết bị thay đổi. Tuỳ chọn này cho phép bạn gửi dữ liệu đã sửa đổi từ thiết bị đến máy chủ. Tuỳ chọn này đặc biệt hữu ích nếu bạn cần đảm bảo rằng máy chủ luôn có dữ liệu mới nhất về thiết bị. Tuỳ chọn này dễ triển khai nếu bạn thực sự lưu trữ dữ liệu trong trình cung cấp nội dung của mình. Nếu bạn đang sử dụng một trình cung cấp nội dung giả lập, thì việc phát hiện các thay đổi về dữ liệu có thể khó khăn hơn.
Theo định kỳ
Chạy bộ chuyển đổi đồng bộ hoá sau khi hết hạn một khoảng thời gian bạn chọn hoặc chạy bộ chuyển đổi đồng bộ hoá vào một thời điểm nhất định hằng ngày.
Theo yêu cầu
Chạy bộ điều hợp đồng bộ hoá để phản hồi hành động của người dùng. Tuy nhiên, để cung cấp trải nghiệm người dùng tốt nhất, bạn nên chủ yếu dựa vào một trong nhiều tuỳ chọn tự động hơn. Bằng cách sử dụng các tuỳ chọn tự động, bạn sẽ tiết kiệm được pin và tài nguyên mạng.

Phần còn lại của bài học này sẽ mô tả chi tiết hơn về từng tuỳ chọn.

Chạy bộ điều hợp đồng bộ hoá khi dữ liệu máy chủ thay đổi

Nếu ứng dụng của bạn chuyển dữ liệu từ một máy chủ và dữ liệu máy chủ thay đổi thường xuyên, bạn có thể sử dụng bộ điều hợp đồng bộ hoá để tải xuống nhằm phản hồi các thay đổi về dữ liệu. Để chạy bộ điều hợp đồng bộ hoá, hãy yêu cầu máy chủ gửi một thông báo đặc biệt đến BroadcastReceiver trong ứng dụng của bạn. Để phản hồi thông báo này, hãy gọi ContentResolver.requestSync() để báo hiệu cho khung bộ điều hợp đồng bộ hoá để chạy bộ điều hợp đồng bộ hoá.

Giải pháp gửi thông báo qua đám mây của Google (GCM) cung cấp cả thành phần máy chủ và thiết bị mà bạn cần để hệ thống nhắn tin này hoạt động. Việc sử dụng GCM để kích hoạt quá trình chuyển sẽ đáng tin cậy và hiệu quả hơn so với máy chủ thăm dò trạng thái. Trong khi thăm dò ý kiến đòi hỏi một Service luôn hoạt động thì GCM sử dụng BroadcastReceiver được kích hoạt khi có tin nhắn đến. Trong khi cuộc thăm dò ý kiến định kỳ sẽ sử dụng pin ngay cả khi không có bản cập nhật, nhưng GCM chỉ gửi thông báo khi cần.

Lưu ý: Nếu bạn sử dụng GCM để kích hoạt bộ điều hợp đồng bộ hoá qua thông báo truyền tin tới tất cả thiết bị cài đặt ứng dụng của bạn, hãy nhớ rằng họ nhận được tin nhắn của bạn gần như cùng một lúc. Trường hợp này có thể khiến nhiều thực thể của bộ điều hợp đồng bộ hoá chạy cùng lúc, gây ra tình trạng quá tải máy chủ và mạng. Để tránh trường hợp này truyền tin đến tất cả thiết bị, bạn nên xem xét việc trì hoãn thời gian khởi động bộ điều hợp đồng bộ hoá trong một khoảng thời gian riêng của từng thiết bị.

Đoạn mã sau đây cho bạn biết cách chạy requestSync() để phản hồi tin nhắn GCM đến:

Kotlin

...
// Constants
// Content provider authority
const val AUTHORITY = "com.example.android.datasync.provider"
// Account type
const val ACCOUNT_TYPE = "com.example.android.datasync"
// Account
const val ACCOUNT = "default_account"
// Incoming Intent key for extended data
const val KEY_SYNC_REQUEST = "com.example.android.datasync.KEY_SYNC_REQUEST"
...
class GcmBroadcastReceiver : BroadcastReceiver() {
    ...
    override fun onReceive(context: Context, intent: Intent) {
        // Get a GCM object instance
        val gcm: GoogleCloudMessaging = GoogleCloudMessaging.getInstance(context)
        // Get the type of GCM message
        val messageType: String? = gcm.getMessageType(intent)
        /*
         * Test the message type and examine the message contents.
         * Since GCM is a general-purpose messaging system, you
         * may receive normal messages that don't require a sync
         * adapter run.
         * The following code tests for a a boolean flag indicating
         * that the message is requesting a transfer from the device.
         */
        if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE == messageType
            && intent.getBooleanExtra(KEY_SYNC_REQUEST, false)) {
            /*
             * Signal the framework to run your sync adapter. Assume that
             * app initialization has already created the account.
             */
            ContentResolver.requestSync(mAccount, AUTHORITY, null)
            ...
        }
        ...
    }
    ...
}

Java

public class GcmBroadcastReceiver extends BroadcastReceiver {
    ...
    // Constants
    // Content provider authority
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Account type
    public static final String ACCOUNT_TYPE = "com.example.android.datasync";
    // Account
    public static final String ACCOUNT = "default_account";
    // Incoming Intent key for extended data
    public static final String KEY_SYNC_REQUEST =
            "com.example.android.datasync.KEY_SYNC_REQUEST";
    ...
    @Override
    public void onReceive(Context context, Intent intent) {
        // Get a GCM object instance
        GoogleCloudMessaging gcm =
                GoogleCloudMessaging.getInstance(context);
        // Get the type of GCM message
        String messageType = gcm.getMessageType(intent);
        /*
         * Test the message type and examine the message contents.
         * Since GCM is a general-purpose messaging system, you
         * may receive normal messages that don't require a sync
         * adapter run.
         * The following code tests for a a boolean flag indicating
         * that the message is requesting a transfer from the device.
         */
        if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)
            &&
            intent.getBooleanExtra(KEY_SYNC_REQUEST)) {
            /*
             * Signal the framework to run your sync adapter. Assume that
             * app initialization has already created the account.
             */
            ContentResolver.requestSync(mAccount, AUTHORITY, null);
            ...
        }
        ...
    }
    ...
}

Chạy bộ điều hợp đồng bộ hoá khi dữ liệu của nhà cung cấp nội dung thay đổi

Nếu ứng dụng của bạn thu thập dữ liệu trong một nhà cung cấp nội dung và bạn muốn cập nhật máy chủ mỗi khi cập nhật nhà cung cấp đó, thì bạn có thể thiết lập để ứng dụng tự động chạy bộ điều hợp đồng bộ hoá. Để thực hiện việc này, bạn đăng ký một đối tượng tiếp nhận dữ liệu cho trình cung cấp nội dung. Khi dữ liệu trong trình cung cấp nội dung của bạn thay đổi, khung trình cung cấp nội dung sẽ gọi đối tượng tiếp nhận dữ liệu. Trong trình quan sát, hãy gọi requestSync() để yêu cầu khung chạy bộ điều hợp đồng bộ hoá.

Lưu ý: Nếu đang sử dụng trình cung cấp nội dung giả lập, thì bạn sẽ không có dữ liệu nào trong trình cung cấp nội dung này và onChange() sẽ không bao giờ được gọi. Trong trường hợp này, bạn phải cung cấp cơ chế của riêng mình để phát hiện các thay đổi đối với dữ liệu thiết bị. Cơ chế này cũng chịu trách nhiệm gọi requestSync() khi dữ liệu thay đổi.

Để tạo đối tượng tiếp nhận dữ liệu cho trình cung cấp nội dung của bạn, hãy mở rộng lớp ContentObserver và triển khai cả hai dạng của phương thức onChange(). Trong onChange(), hãy gọi requestSync() để khởi động bộ điều hợp đồng bộ hoá.

Để đăng ký trình quan sát, hãy truyền trình quan sát đó làm đối số trong lệnh gọi đến registerContentObserver(). Trong lệnh gọi này, bạn cũng phải truyền một URI nội dung cho dữ liệu mà bạn muốn xem. Khung của nhà cung cấp nội dung sẽ so sánh URI đồng hồ này với các URI nội dung được truyền dưới dạng đối số cho các phương thức ContentResolver để sửa đổi nhà cung cấp của bạn, chẳng hạn như ContentResolver.insert(). Nếu khớp, quá trình triển khai ContentObserver.onChange() sẽ được gọi.

Đoạn mã sau đây cho bạn biết cách xác định ContentObserver gọi requestSync() khi một bảng thay đổi:

Kotlin

// Constants
// Content provider scheme
const val SCHEME = "content://"
// Content provider authority
const val AUTHORITY = "com.example.android.datasync.provider"
// Path for the content provider table
const val TABLE_PATH = "data_table"
...
class MainActivity : FragmentActivity() {
    ...
    // A content URI for the content provider's data table
    private lateinit var uri: Uri
    // A content resolver for accessing the provider
    private lateinit var mResolver: ContentResolver
    ...
    inner class TableObserver(...) : ContentObserver(...) {
        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         * This method signature is provided for compatibility with
         * older platforms.
         */
        override fun onChange(selfChange: Boolean) {
            /*
             * Invoke the method signature available as of
             * Android platform version 4.1, with a null URI.
             */
            onChange(selfChange, null)
        }

        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         */
        override fun onChange(selfChange: Boolean, changeUri: Uri?) {
            /*
             * Ask the framework to run your sync adapter.
             * To maintain backward compatibility, assume that
             * changeUri is null.
             */
            ContentResolver.requestSync(account, AUTHORITY, null)
        }
        ...
    }
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        // Get the content resolver object for your app
        mResolver = contentResolver
        // Construct a URI that points to the content provider data table
        uri = Uri.Builder()
                .scheme(SCHEME)
                .authority(AUTHORITY)
                .path(TABLE_PATH)
                .build()
        /*
         * Create a content observer object.
         * Its code does not mutate the provider, so set
         * selfChange to "false"
         */
        val observer = TableObserver(false)
        /*
         * Register the observer for the data table. The table's path
         * and any of its subpaths trigger the observer.
         */
        mResolver.registerContentObserver(uri, true, observer)
        ...
    }
    ...
}

Java

public class MainActivity extends FragmentActivity {
    ...
    // Constants
    // Content provider scheme
    public static final String SCHEME = "content://";
    // Content provider authority
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Path for the content provider table
    public static final String TABLE_PATH = "data_table";
    // Account
    public static final String ACCOUNT = "default_account";
    // Global variables
    // A content URI for the content provider's data table
    Uri uri;
    // A content resolver for accessing the provider
    ContentResolver mResolver;
    ...
    public class TableObserver extends ContentObserver {
        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         * This method signature is provided for compatibility with
         * older platforms.
         */
        @Override
        public void onChange(boolean selfChange) {
            /*
             * Invoke the method signature available as of
             * Android platform version 4.1, with a null URI.
             */
            onChange(selfChange, null);
        }
        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         */
        @Override
        public void onChange(boolean selfChange, Uri changeUri) {
            /*
             * Ask the framework to run your sync adapter.
             * To maintain backward compatibility, assume that
             * changeUri is null.
             */
            ContentResolver.requestSync(mAccount, AUTHORITY, null);
        }
        ...
    }
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Get the content resolver object for your app
        mResolver = getContentResolver();
        // Construct a URI that points to the content provider data table
        uri = new Uri.Builder()
                  .scheme(SCHEME)
                  .authority(AUTHORITY)
                  .path(TABLE_PATH)
                  .build();
        /*
         * Create a content observer object.
         * Its code does not mutate the provider, so set
         * selfChange to "false"
         */
        TableObserver observer = new TableObserver(false);
        /*
         * Register the observer for the data table. The table's path
         * and any of its subpaths trigger the observer.
         */
        mResolver.registerContentObserver(uri, true, observer);
        ...
    }
    ...
}

Chạy bộ điều hợp đồng bộ hoá định kỳ

Bạn có thể chạy bộ điều hợp đồng bộ hoá định kỳ bằng cách đặt một khoảng thời gian để đợi giữa các lần chạy, hoặc chạy bộ điều hợp đồng bộ hoá vào những thời điểm nhất định trong ngày hoặc cả hai. Việc chạy bộ điều hợp đồng bộ hoá định kỳ cho phép bạn ước chừng khoảng thời gian giữa những lần cập nhật của máy chủ.

Tương tự, bạn có thể tải dữ liệu lên từ thiết bị khi máy chủ của bạn tương đối không hoạt động, bằng cách lên lịch để bộ điều hợp đồng bộ hoá chạy vào ban đêm. Hầu hết người dùng bật nguồn và cắm sạc vào ban đêm, vì vậy, thời gian này thường có sẵn. Hơn nữa, thiết bị không chạy tác vụ khác cùng lúc với bộ điều hợp đồng bộ hoá của bạn. Tuy nhiên, nếu áp dụng phương pháp này, bạn cần đảm bảo rằng mỗi thiết bị kích hoạt quá trình chuyển dữ liệu vào một thời điểm hơi khác nhau. Nếu tất cả các thiết bị chạy bộ điều hợp đồng bộ hoá cùng một lúc, bạn có thể sẽ làm quá tải mạng dữ liệu của máy chủ và nhà cung cấp dịch vụ di động.

Nhìn chung, các lần chạy định kỳ sẽ hợp lý nếu người dùng không cần cập nhật tức thì nhưng muốn nhận được các bản cập nhật định kỳ. Việc chạy định kỳ cũng sẽ hợp lý nếu bạn muốn cân bằng giữa khả năng cung cấp dữ liệu mới nhất với hiệu suất của các lần chạy bộ chuyển đổi đồng bộ hoá nhỏ hơn mà không sử dụng quá nhiều tài nguyên của thiết bị.

Để chạy bộ điều hợp đồng bộ hoá theo định kỳ, hãy gọi addPeriodicSync(). Thao tác này sẽ lên lịch chạy bộ điều hợp đồng bộ hóa sau một khoảng thời gian nhất định. Vì khung bộ điều hợp đồng bộ hoá phải tính đến các hoạt động thực thi bộ điều hợp đồng bộ khác và cố gắng tăng tối đa hiệu suất pin, nên thời gian đã trôi qua có thể chênh lệch vài giây. Ngoài ra, khung này sẽ không chạy bộ điều hợp đồng bộ hoá nếu không có mạng.

Xin lưu ý rằng addPeriodicSync() không chạy bộ điều hợp đồng bộ hoá vào một thời điểm cụ thể trong ngày. Để chạy bộ điều hợp đồng bộ hoá gần như cùng một lúc mỗi ngày, hãy sử dụng chuông báo lặp lại làm điều kiện kích hoạt. Chuông báo lặp lại được mô tả chi tiết hơn trong tài liệu tham khảo về AlarmManager. Nếu sử dụng phương thức setInexactRepeating() để đặt các điều kiện kích hoạt theo thời gian trong ngày có một số biến thể, bạn vẫn nên ngẫu nhiên thời gian bắt đầu để đảm bảo rằng bộ chuyển đổi đồng bộ hoá chạy từ các thiết bị khác nhau được so le.

Phương thức addPeriodicSync() không vô hiệu hoá setSyncAutomatically(), vì vậy, bạn có thể thấy nhiều lần đồng bộ hoá chạy trong một khoảng thời gian tương đối ngắn. Ngoài ra, chỉ một số cờ điều khiển bộ chuyển đổi đồng bộ hoá được cho phép trong lệnh gọi đến addPeriodicSync(). Các cờ không được phép được mô tả trong tài liệu tham khảo dành cho addPeriodicSync().

Đoạn mã sau đây hướng dẫn bạn cách lên lịch chạy bộ chuyển đổi đồng bộ hoá định kỳ:

Kotlin

// Content provider authority
const val AUTHORITY = "com.example.android.datasync.provider"
// Account
const val ACCOUNT = "default_account"
// Sync interval constants
const val SECONDS_PER_MINUTE = 60L
const val SYNC_INTERVAL_IN_MINUTES = 60L
const val SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * SECONDS_PER_MINUTE
...
class MainActivity : FragmentActivity() {
    ...
    // A content resolver for accessing the provider
    private lateinit var mResolver: ContentResolver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        // Get the content resolver for your app
        mResolver = contentResolver
        /*
         * Turn on periodic syncing
         */
        ContentResolver.addPeriodicSync(
                mAccount,
                AUTHORITY,
                Bundle.EMPTY,
                SYNC_INTERVAL)
        ...
    }
    ...
}

Java

public class MainActivity extends FragmentActivity {
    ...
    // Constants
    // Content provider authority
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Account
    public static final String ACCOUNT = "default_account";
    // Sync interval constants
    public static final long SECONDS_PER_MINUTE = 60L;
    public static final long SYNC_INTERVAL_IN_MINUTES = 60L;
    public static final long SYNC_INTERVAL =
            SYNC_INTERVAL_IN_MINUTES *
            SECONDS_PER_MINUTE;
    // Global variables
    // A content resolver for accessing the provider
    ContentResolver mResolver;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Get the content resolver for your app
        mResolver = getContentResolver();
        /*
         * Turn on periodic syncing
         */
        ContentResolver.addPeriodicSync(
                mAccount,
                AUTHORITY,
                Bundle.EMPTY,
                SYNC_INTERVAL);
        ...
    }
    ...
}

Chạy bộ điều hợp đồng bộ hoá theo yêu cầu

Để chạy bộ điều hợp đồng bộ hoá, việc chạy bộ điều hợp đồng bộ hoá để phản hồi yêu cầu của người dùng là chiến lược ít được ưa thích nhất. Khung này được thiết kế đặc biệt để tiết kiệm pin khi chạy bộ điều hợp đồng bộ hoá theo lịch biểu. Các tuỳ chọn chạy quá trình đồng bộ hoá để phản hồi thay đổi về dữ liệu sẽ sử dụng hiệu quả pin, vì nguồn pin được dùng để cung cấp dữ liệu mới.

So với việc cho phép người dùng chạy tính năng đồng bộ hoá theo yêu cầu, quá trình đồng bộ hoá sẽ tự chạy, do đó sử dụng không hiệu quả tài nguyên mạng và nguồn điện. Ngoài ra, việc cung cấp tính năng đồng bộ hoá theo yêu cầu sẽ khiến người dùng yêu cầu đồng bộ hoá ngay cả khi không có bằng chứng cho thấy dữ liệu đã thay đổi và việc chạy quy trình đồng bộ hoá không làm mới dữ liệu sẽ sử dụng không hiệu quả pin. Nhìn chung, ứng dụng của bạn nên sử dụng các tín hiệu khác để kích hoạt quá trình đồng bộ hoá hoặc lên lịch định kỳ mà không cần hoạt động đồng bộ hoá của người dùng.

Tuy nhiên, nếu bạn vẫn muốn chạy bộ điều hợp đồng bộ hoá theo yêu cầu, hãy đặt cờ bộ điều hợp đồng bộ hoá để chạy bộ điều hợp đồng bộ hoá thủ công, sau đó gọi ContentResolver.requestSync().

Chạy lệnh chuyển dữ liệu theo yêu cầu bằng các cờ sau:

SYNC_EXTRAS_MANUAL
Buộc đồng bộ hoá thủ công. Khung bộ điều hợp đồng bộ hoá bỏ qua các chế độ cài đặt hiện có, chẳng hạn như cờ do setSyncAutomatically() đặt.
SYNC_EXTRAS_EXPEDITED
Buộc quá trình đồng bộ hoá bắt đầu ngay lập tức. Nếu bạn không đặt chế độ này, hệ thống có thể đợi vài giây trước khi chạy yêu cầu đồng bộ hoá. Lý do là hệ thống cố gắng tối ưu hoá mức sử dụng pin bằng cách lên lịch cho nhiều yêu cầu trong một khoảng thời gian ngắn.

Đoạn mã sau đây cho bạn biết cách gọi requestSync() để phản hồi cho một lượt nhấp vào nút:

Kotlin

// Constants
// Content provider authority
val AUTHORITY = "com.example.android.datasync.provider"
// Account type
val ACCOUNT_TYPE = "com.example.android.datasync"
// Account
val ACCOUNT = "default_account"
...
class MainActivity : FragmentActivity() {
    ...
    // Instance fields
    private lateinit var mAccount: Account
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        /*
         * Create the placeholder account. The code for CreateSyncAccount
         * is listed in the lesson Creating a Sync Adapter
         */

        mAccount = createSyncAccount()
        ...
    }

    /**
     * Respond to a button click by calling requestSync(). This is an
     * asynchronous operation.
     *
     * This method is attached to the refresh button in the layout
     * XML file
     *
     * @param v The View associated with the method call,
     * in this case a Button
     */
    fun onRefreshButtonClick(v: View) {
        // Pass the settings flags by inserting them in a bundle
        val settingsBundle = Bundle().apply {
            putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true)
            putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true)
        }
        /*
         * Request the sync for the default account, authority, and
         * manual sync settings
         */
        ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle)
    }

Java

public class MainActivity extends FragmentActivity {
    ...
    // Constants
    // Content provider authority
    public static final String AUTHORITY =
            "com.example.android.datasync.provider";
    // Account type
    public static final String ACCOUNT_TYPE = "com.example.android.datasync";
    // Account
    public static final String ACCOUNT = "default_account";
    // Instance fields
    Account mAccount;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        /*
         * Create the placeholder account. The code for CreateSyncAccount
         * is listed in the lesson Creating a Sync Adapter
         */

        mAccount = CreateSyncAccount(this);
        ...
    }
    /**
     * Respond to a button click by calling requestSync(). This is an
     * asynchronous operation.
     *
     * This method is attached to the refresh button in the layout
     * XML file
     *
     * @param v The View associated with the method call,
     * in this case a Button
     */
    public void onRefreshButtonClick(View v) {
        // Pass the settings flags by inserting them in a bundle
        Bundle settingsBundle = new Bundle();
        settingsBundle.putBoolean(
                ContentResolver.SYNC_EXTRAS_MANUAL, true);
        settingsBundle.putBoolean(
                ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        /*
         * Request the sync for the default account, authority, and
         * manual sync settings
         */
        ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
    }