The Android Developer Challenge is back! Submit your idea before December 2.

Menggambar tampilan jam

Setelah mengonfigurasi project dan menambahkan class yang mengimplementasikan layanan tampilan jam, Anda dapat mulai menulis kode untuk menginisialisasi dan menggambar tampilan jam kustom.

Pelajaran ini mencakup contoh-contoh dari sampel Tampilan Jam untuk menunjukkan cara sistem menggunakan layanan tampilan jam. Banyak aspek dari implementasi layanan yang dijelaskan di sini (seperti inisialisasi dan deteksi fitur perangkat) berlaku untuk semua tampilan jam, sehingga Anda dapat menggunakan kembali sebagian kodenya pada tampilan jam Anda sendiri.

Gambar 1. Tampilan jam analog dan digital dalam contoh Tampilan Jam.

Menginisialisasi tampilan jam

Setelah sistem memuat layanan Anda, Anda harus mengalokasikan dan menginisialisasi sebagian besar resource yang diperlukan tampilan jam, termasuk memuat resource bitmap, membuat objek timer untuk menjalankan animasi kustom, mengonfigurasi gaya warna, dan menjalankan komputasi lainnya. Biasanya Anda cukup menjalankan operasi ini sekali, dan menggunakan hasilnya berkali-kali. Praktik ini meningkatkan performa tampilan jam dan mempermudahkan pengelolaan kode.

Untuk menginisialisasi tampilan jam, ikuti langkah-langkah berikut:

  1. Deklarasikan variabel untuk timer kustom, objek visual, dan elemen lainnya.
  2. Inisialisasi elemen tampilan jam dalam metode Engine.onCreate().
  3. Inisialisasi timer kustom dalam metode Engine.onVisibilityChanged().

Bagian berikut menjelaskan langkah-langkah ini secara detail.

Mendeklarasikan variabel

Resource yang Anda inisialisasi saat sistem memuat layanan harus dapat diakses pada beberapa tahap berbeda sepanjang implementasi, agar Anda dapat menggunakannya kembali. Anda dapat mencapainya dengan mendeklarasikan variabel anggota untuk resource ini dalam implementasi WatchFaceService.Engine.

Deklarasikan variabel untuk elemen berikut:

Objek visual
Sebagian besar tampilan jam berisi setidaknya satu gambar bitmap yang digunakan sebagai latar belakang tampilan jam, seperti yang dijelaskan dalam Membuat Strategi Implementasi. Anda dapat menggunakan gambar bitmap tambahan yang mewakili jarum jam atau elemen desain lainnya pada tampilan jam.
Timer periodik
Sistem mengirim notifikasi ke tampilan jam setiap satu menit ketika waktu berubah, tetapi beberapa tampilan jam menjalankan animasi pada interval waktu khusus. Dalam kasus ini, Anda memerlukan timer kustom yang berdetik sesuai dengan frekuensi yang diperlukan untuk memperbarui tampilan jam.
Penerima perubahan zona waktu
Pengguna dapat menyesuaikan zona waktu saat bepergian, dan sistem akan menyiarkan peristiwa ini. Implementasi layanan Anda harus mendaftarkan penerima siaran yang diberi tahu saat zona waktu berubah, dan memperbarui waktu sesuai perubahan itu.

Cuplikan berikut menunjukkan cara menetapkan variabel ini:

Kotlin

    private const val MSG_UPDATE_TIME = 0

    class Service : CanvasWatchFaceService() {
        ...
        inner class Engine : CanvasWatchFaceService.Engine() {

            private lateinit var calendar: Calendar

            // device features
            private var lowBitAmbient: Boolean = false

            // graphic objects
            private lateinit var backgroundBitmap: Bitmap
            private var backgroundScaledBitmap: Bitmap? = null
            private lateinit var hourPaint: Paint
            private lateinit var minutePaint: Paint

            // handler to update the time once a second in interactive mode
            private val updateTimeHandler: Handler = UpdateTimeHandler(WeakReference(this))

            // receiver to update the time zone
            private val timeZoneReceiver: BroadcastReceiver = object : BroadcastReceiver() {
                override fun onReceive(context: Context, intent: Intent) {
                    calendar.timeZone = TimeZone.getDefault()
                    invalidate()
                }
            }

            // service methods (see other sections)
            ...
        }
        ...
        private class UpdateTimeHandler(val engineReference: WeakReference<Engine>) : Handler() {
            override fun handleMessage(message: Message) {
                engineReference.get()?.apply {
                    when (message.what) {
                        MSG_UPDATE_TIME -> {
                            invalidate()
                            if (shouldTimerBeRunning()) {
                                val timeMs: Long = System.currentTimeMillis()
                                val delayMs: Long =
                                        INTERACTIVE_UPDATE_RATE_MS - timeMs % INTERACTIVE_UPDATE_RATE_MS
                                sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs)
                            }
                        }
                    }
                }
            }
        }
        ...
    }
    

Java

    public class CanvasWatchFaceJava extends CanvasWatchFaceService {
        static final int MSG_UPDATE_TIME = 0;
        ...
        class Engine extends CanvasWatchFaceService.Engine {

            Calendar calendar;

            // device features
            boolean lowBitAmbient;

            // graphic objects
            Bitmap backgroundBitmap;
            Bitmap backgroundScaledBitmap;
            Paint hourPaint;
            Paint minutePaint;
            ...

            // handler to update the time once a second in interactive mode
            final Handler updateTimeHandler = new UpdateTimeHandler(new WeakReference<>(this));

            // receiver to update the time zone
            final BroadcastReceiver timeZoneReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    calendar.setTimeZone(TimeZone.getDefault());
                    invalidate();
                }
            };

            // service methods (see other sections)
            ...
        }
        ...
        private static class UpdateTimeHandler extends Handler {
            private WeakReference<Engine> engineReference;

            UpdateTimeHandler(WeakReference<Engine> engine) {
                this.engineReference = engine;
            }

            @Override
            public void handleMessage(Message message) {
                Engine engine = engineReference.get();
                if (engine != null) {
                    switch (message.what) {
                        case MSG_UPDATE_TIME:
                            engine.invalidate();
                            if (engine.shouldTimerBeRunning()) {
                                long timeMs = System.currentTimeMillis();
                                long delayMs = INTERACTIVE_UPDATE_RATE_MS
                                        - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
                                sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
                            }
                            break;
                    }
                }
            }
        }
        ...
    }
    

Dalam contoh di atas, timer kustom diimplementasikan sebagai instance Handler yang mengirimkan dan memproses pesan tertunda menggunakan antrean pesan thread. Untuk tampilan jam khusus ini, timer kustom berdetik setiap satu detik. Ketika timer berjalan, handler akan memanggil metode invalidate() dan sistem kemudian akan memanggil metode onDraw() untuk menggambar ulang tampilan jam.

Menginisialisasi elemen tampilan jam

Setelah mendeklarasikan variabel anggota untuk resource bitmap, gaya warna, dan elemen lain yang Anda gunakan kembali setiap kali menggambar ulang tampilan jam, inisialisasi semuanya ketika sistem memuat layanan Anda. Elemen-elemen ini hanya perlu diinisialisasi sekali dan dapat digunakan berkali-kali, sehingga akan meningkatkan performa dan masa pakai baterai.

Dalam metode Engine.onCreate(), inisialisasi elemen-elemen berikut:

  • Memuat gambar latar.
  • Membuat gaya dan warna untuk menggambar objek visual.
  • Mengalokasikan objek untuk menghitung waktu.
  • Mengonfigurasi UI sistem.

Cuplikan berikut menunjukkan cara menginisialisasi elemen-elemen tersebut:

Kotlin

    override fun onCreate(holder: SurfaceHolder?) {
        super.onCreate(holder)

        // configure the system UI (see next section)
        ...

        // load the background image
        backgroundBitmap = (resources.getDrawable(R.drawable.bg, null) as BitmapDrawable).bitmap

        // create graphic styles
        hourPaint = Paint().apply {
            setARGB(255, 200, 200, 200)
            strokeWidth = 5.0f
            isAntiAlias = true
            strokeCap = Paint.Cap.ROUND
        }
        ...

        // allocate a Calendar to calculate local time using the UTC time and time zone
        calendar = Calendar.getInstance()
    }
    

Java

    @Override
    public void onCreate(SurfaceHolder holder) {
        super.onCreate(holder);

        // configure the system UI (see next section)
        ...

        // load the background image
        Resources resources = AnalogWatchFaceService.this.getResources();
        Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null);
        backgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();

        // create graphic styles
        hourPaint = new Paint();
        hourPaint.setARGB(255, 200, 200, 200);
        hourPaint.setStrokeWidth(5.0f);
        hourPaint.setAntiAlias(true);
        hourPaint.setStrokeCap(Paint.Cap.ROUND);
        ...

        // allocate a Calendar to calculate local time using the UTC time and time zone
        calendar = Calendar.getInstance();
    }
    

Bitmap latar belakang dimuat hanya sekali ketika sistem menginisialisasi tampilan jam. Gaya visualnya adalah instance dari class Paint. Gunakan gaya ini untuk menggambar elemen tampilan jam dalam metode Engine.onDraw(), seperti yang dijelaskan dalam Menggambar Tampilan Jam Anda.

Menginisialisasi timer kustom

Sebagai developer tampilan jam, Anda menentukan seberapa sering tampilan jam perlu diperbarui dengan menyediakan timer kustom yang berdetik sesuai frekuensi yang diperlukan selagi perangkat dalam mode interaktif. Hal ini memungkinkan Anda membuat animasi kustom dan efek visual lainnya.

Catatan: Dalam mode standby, sistem tidak dapat memanggil timer kustom dengan andal. Untuk memperbarui tampilan jam dalam mode standby, lihat Memperbarui tampilan jam dalam mode standby.

Contoh definisi timer dari class AnalogWatchFaceService yang berdetik setiap satu detik dapat dilihat dalam Mendeklarasikan variabel. Dalam metode Engine.onVisibilityChanged(), mulai timer kustom jika kedua kondisi berikut terpenuhi:

  • Tampilan jam terlihat.
  • Perangkat sedang dalam mode interaktif.

Class AnalogWatchFaceService menjadwalkan detikan timer berikutnya jika diperlukan sebagai berikut:

Kotlin

    private fun updateTimer() {
        updateTimeHandler.removeMessages(MSG_UPDATE_TIME)
        if (shouldTimerBeRunning()) {
            updateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME)
        }
    }

    fun shouldTimerBeRunning(): Boolean = isVisible && !isInAmbientMode
    

Java

    private void updateTimer() {
        updateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        if (shouldTimerBeRunning()) {
            updateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
        }
    }

    boolean shouldTimerBeRunning() {
        return isVisible() && !isInAmbientMode();
    }
    

Timer kustom ini berdetik setiap satu detik, seperti yang dijelaskan dalam Mendeklarasikan variabel.

Dalam metode onVisibilityChanged(), mulai timer jika diperlukan dan daftarkan penerima untuk perubahan zona waktu seperti berikut:

Kotlin

    override fun onVisibilityChanged(visible: Boolean) {
        super.onVisibilityChanged(visible)

        if (visible) {
            registerReceiver()

            // Update time zone in case it changed while we weren't visible.
            calendar.timeZone = TimeZone.getDefault()
        } else {
            unregisterReceiver()
        }

        // Whether the timer should be running depends on whether we're visible and
        // whether we're in ambient mode, so we may need to start or stop the timer
        updateTimer()
    }
    

Java

    @Override
    public void onVisibilityChanged(boolean visible) {
        super.onVisibilityChanged(visible);

        if (visible) {
            registerReceiver();

            // Update time zone in case it changed while we weren't visible.
            calendar.setTimeZone(TimeZone.getDefault());
        } else {
            unregisterReceiver();
        }

        // Whether the timer should be running depends on whether we're visible and
        // whether we're in ambient mode, so we may need to start or stop the timer
        updateTimer();
    }
    

Jika tampilan jam terlihat, metode onVisibilityChanged() akan mendaftarkan penerima untuk perubahan zona waktu. Jika perangkat dalam mode interaktif, metode ini juga akan memulai timer kustom. Jika tampilan jam tidak terlihat, metode ini akan menghentikan timer kustom dan membatalkan pendaftaran penerima untuk perubahan zona waktu. Metode registerReceiver() dan unregisterReceiver() diimplementasikan sebagai berikut:

Kotlin

    private fun registerReceiver() {
        if (registeredTimeZoneReceiver) return
        registeredTimeZoneReceiver = true
        IntentFilter(Intent.ACTION_TIMEZONE_CHANGED).also { filter ->
            this@AnalogWatchFaceService.registerReceiver(timeZoneReceiver, filter)
        }
    }

    private fun unregisterReceiver() {
        if (!registeredTimeZoneReceiver) return
        registeredTimeZoneReceiver = false
        this@AnalogWatchFaceService.unregisterReceiver(timeZoneReceiver)
    }
    

Java

    private void registerReceiver() {
        if (registeredTimeZoneReceiver) {
            return;
        }
        registeredTimeZoneReceiver = true;
        IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
        AnalogWatchFaceService.this.registerReceiver(timeZoneReceiver, filter);
    }

    private void unregisterReceiver() {
        if (!registeredTimeZoneReceiver) {
            return;
        }
        registeredTimeZoneReceiver = false;
        AnalogWatchFaceService.this.unregisterReceiver(timeZoneReceiver);
    }
    

Memperbarui tampilan jam dalam mode standby

Dalam mode standby, sistem akan memanggil metode Engine.onTimeTick() setiap menit. Dalam mode ini biasanya tampilan jam cukup diperbarui sekali per menit. Untuk memperbarui tampilan jam saat dalam mode interaktif, Anda harus memberikan timer kustom seperti yang dijelaskan dalam Menginisialisasi timer kustom.

Dalam mode standby, sebagian besar implementasi tampilan jam akan langsung membatalkan validasi kanvas untuk menggambar ulang tampilan jam dalam metode Engine.onTimeTick():

Kotlin

    override fun onTimeTick() {
        super.onTimeTick()

        invalidate()
    }
    

Java

    @Override
    public void onTimeTick() {
        super.onTimeTick();

        invalidate();
    }
    

Mengonfigurasi UI sistem

Tampilan jam tidak boleh mengganggu elemen UI sistem, seperti yang dijelaskan dalam Mengakomodasi Elemen UI Sistem. Jika tampilan jam memiliki latar belakang terang atau menampilkan informasi di dekat bagian bawah layar, Anda mungkin perlu mengonfigurasi ukuran kartu notifikasi atau mengaktifkan perlindungan latar belakang.

Dengan Wear OS by Google, Anda dapat mengonfigurasi aspek-aspek UI sistem berikut ketika tampilan jam Anda aktif:

  • Menentukan apakah sistem menggambar waktu di tampilan jam.
  • Melindungi indikator sistem dengan latar belakang solid di sekitarnya.
  • Menentukan posisi indikator sistem.

Untuk mengonfigurasi aspek-aspek UI sistem ini, buat instance WatchFaceStyle, lalu teruskan ke metode Engine.setWatchFaceStyle().

Class AnalogWatchFaceService mengonfigurasi UI sistem sebagai berikut:

Kotlin

    override fun onCreate(holder: SurfaceHolder?) {
        super.onCreate(holder)

        // configure the system UI
        setWatchFaceStyle(WatchFaceStyle.Builder(this@AnalogWatchFaceService)
                .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build())
        ...
    }
    

Java

    @Override
    public void onCreate(SurfaceHolder holder) {
        super.onCreate(holder);

        // configure the system UI
        setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
                .setBackgroundVisibility(WatchFaceStyle
                                        .BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build());
        ...
    }
    

Cuplikan kode di atas mengonfigurasi waktu sistem agar tidak ditampilkan (karena tampilan jam ini menggambar representasi waktunya sendiri).

Anda dapat mengonfigurasi gaya UI sistem kapan saja dalam implementasi tampilan jam Anda. Misalnya, jika pengguna memilih latar belakang putih, Anda dapat menambahkan perlindungan latar belakang untuk indikator sistem.

Untuk detail selengkapnya tentang mengonfigurasi UI sistem, lihat dokumentasi referensi Wear API.

Mengelola indikator notifikasi belum dibaca

Sering kali pengguna ingin melihat indikasi yang jelas bahwa ada notifikasi yang belum dibaca. Karena itulah indikator notifikasi belum dibaca disediakan. Indikator ini terlihat seperti titik yang dilingkari di bagian bawah layar. Indikator ditampilkan jika ada lebih dari satu notifikasi yang belum dibaca dalam aliran.

indikator notifikasi belum dibaca

Gambar 2. Indikator notifikasi belum dibaca.

Catatan: Indikator notifikasi belum dibaca tidak diaktifkan pada Wear 2.8.0 versi produksi. Developer disarankan untuk menguji implementasinya menggunakan emulator Wear terbaru. Fitur ini baru akan ditampilkan secara default mulai dari rilis Wear versi konsumen berikutnya (versi 2.9.0).

Secara default, indikator ini akan ditambahkan ke tampilan jam Anda. Kami sangat menganjurkan agar Anda membiarkan indikator tersebut tersedia bagi pengguna. Namun, jika tampilan jam Anda sudah menyediakan indikasi notifikasi belum dibaca, atau jika posisi indikator baru bentrok dengan elemen tampilan jam, Anda dapat memilih untuk tidak menampilkan indikator sistem. Gunakan salah satu metode berikut saat membuat tampilan jam:

masukkan jumlah notifikasi belum dibaca kustom masukkan jumlah notifikasi belum dibaca di status bar

Gambar 3. Jumlah notifikasi kustom atau jumlah notifikasi status bar.

Jika ingin menampilkan indikator notifikasi yang belum dibaca pada tampilan jam, Anda dapat menyesuaikan warna lingkaran luarnya. Panggil WatchFaceStyle.Builder.setAccentColor dan tentukan color yang diinginkan. Secara default, lingkaran luar berwarna putih.

Mendapatkan informasi tentang layar perangkat

Sistem akan memanggil metode Engine.onPropertiesChanged() ketika menentukan properti layar perangkat, misalnya apakah perangkat menggunakan mode standby bit rendah dan apakah layar membutuhkan anti burn-in.

Cuplikan kode berikut menunjukkan cara mendapatkan properti ini:

Kotlin

    override fun onPropertiesChanged(properties: Bundle?) {
        super.onPropertiesChanged(properties)
        properties?.apply {
            lowBitAmbient = getBoolean(PROPERTY_LOW_BIT_AMBIENT, false)
            burnInProtection = getBoolean(PROPERTY_BURN_IN_PROTECTION, false)
        }
    }
    

Java

    @Override
    public void onPropertiesChanged(Bundle properties) {
        super.onPropertiesChanged(properties);
        lowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
        burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION,
                false);
    }
    

Anda harus mempertimbangkan properti perangkat berikut saat menggambar tampilan jam:

  • Untuk perangkat yang menggunakan mode standby bit rendah, layar mendukung bit yang lebih sedikit untuk setiap warna dalam mode standby, sehingga Anda harus menonaktifkan anti-aliasing dan pemfilteran bitmap saat perangkat beralih ke mode standby.
  • Untuk perangkat yang memerlukan anti burn-in, hindari menggunakan blok piksel putih yang luas dalam mode standby dan jangan menempatkan konten dalam jarak 10 piksel dari tepi layar, karena sistem akan menggeser konten secara berkala untuk menghindari terjadinya burn-in piksel.

Untuk informasi lebih lanjut tentang mode standby bit rendah dan anti burn-in, lihat Mengoptimalkan untuk Layar Khusus. Untuk informasi lebih lanjut cara menonaktifkan pemfilteran bitmap, lihat Pemfilteran Bitmap.

Merespons perubahan antarmode

Ketika perangkat beralih antara mode standby dan interaktif, sistem akan memanggil metode Engine.onAmbientModeChanged(). Implementasi layanan Anda harus melakukan penyesuaian yang diperlukan untuk beralih antara mode tersebut, lalu memanggil metode invalidate() agar sistem menggambar ulang tampilan jam.

Cuplikan berikut menunjukkan cara menerapkan metode ini:

Kotlin

    override fun onAmbientModeChanged(inAmbientMode: Boolean) {

        super.onAmbientModeChanged(inAmbientMode)

        if (lowBitAmbient) {
            !inAmbientMode.also { antiAlias ->
                hourPaint.isAntiAlias = antiAlias
                minutePaint.isAntiAlias = antiAlias
                secondPaint.isAntiAlias = antiAlias
                tickPaint.isAntiAlias = antiAlias
            }
        }
        invalidate()
        updateTimer()
    }
    

Java

    @Override
    public void onAmbientModeChanged(boolean inAmbientMode) {

        super.onAmbientModeChanged(inAmbientMode);

        if (lowBitAmbient) {
            boolean antiAlias = !inAmbientMode;
            hourPaint.setAntiAlias(antiAlias);
            minutePaint.setAntiAlias(antiAlias);
            secondPaint.setAntiAlias(antiAlias);
            tickPaint.setAntiAlias(antiAlias);
        }
        invalidate();
        updateTimer();
    }
    

Contoh ini membuat penyesuaian pada beberapa gaya visual dan membatalkan validasi kanvas agar sistem dapat menggambar ulang tampilan jam.

Menggambar tampilan jam

Untuk menggambar tampilan jam kustom, sistem akan memanggil metode Engine.onDraw() dengan instance Canvas dan batasan untuk menggambar tampilan jam Anda. Batasan tersebut memperhitungkan area inset, seperti "dagu" di bagian bawah beberapa perangkat berlayar lingkaran. Anda dapat menggunakan kanvas ini untuk menggambar tampilan jam secara langsung sebagai berikut:

  1. Ganti metode onSurfaceChanged() untuk menskalakan latar belakang agar sesuai dengan perangkat setiap kali tampilan berubah.

    Kotlin

        override fun onSurfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
            if (backgroundScaledBitmap?.width != width || backgroundScaledBitmap?.height != height) {
                backgroundScaledBitmap = Bitmap.createScaledBitmap(backgroundBitmap,
                        width, height, true /* filter */)
            }
            super.onSurfaceChanged(holder, format, width, height)
        }
        

    Java

        @Override
        public void onSurfaceChanged(
                SurfaceHolder holder, int format, int width, int height) {
            if (backgroundScaledBitmap == null
                    || backgroundScaledBitmap.getWidth() != width
                    || backgroundScaledBitmap.getHeight() != height) {
                backgroundScaledBitmap = Bitmap.createScaledBitmap(backgroundBitmap,
                        width, height, true /* filter */);
            }
            super.onSurfaceChanged(holder, format, width, height);
        }
        
  2. Periksa apakah perangkat berada dalam mode standby atau mode interaktif.
  3. Lakukan semua komputasi visual yang diperlukan.
  4. Gambar bitmap latar belakang Anda di atas kanvas.
  5. Gunakan metode dalam class Canvas untuk menggambar tampilan jam Anda.

Cuplikan berikut menunjukkan cara mengimplementasikan metode onDraw():

Kotlin

    override fun onDraw(canvas: Canvas, bounds: Rect) {
        val frameStartTimeMs: Long = SystemClock.elapsedRealtime()

        // Drawing code here

        if (shouldTimerBeRunning()) {
            var delayMs: Long = SystemClock.elapsedRealtime() - frameStartTimeMs
            delayMs = if (delayMs > INTERACTIVE_UPDATE_RATE_MS) {
                // This scenario occurs when drawing all of the components takes longer than an actual
                // frame. It may be helpful to log how many times this happens, so you can
                // fix it when it occurs.
                // In general, you don't want to redraw immediately, but on the next
                // appropriate frame (else block below).
                0
            } else {
                // Sets the delay as close as possible to the intended framerate.
                // Note that the recommended interactive update rate is 1 frame per second.
                // However, if you want to include the sweeping hand gesture, set the
                // interactive update rate up to 30 frames per second.
                INTERACTIVE_UPDATE_RATE_MS - delayMs
            }
            updateTimeHandler.sendEmptyMessageDelayed(MSG_CODE_UPDATE_TIME, delayMs)
        }
    }
    

Java

    @Override
    public void onDraw(Canvas canvas, Rect bounds) {
        long frameStartTimeMs = SystemClock.elapsedRealtime();

        // Drawing code here

        if (shouldTimerBeRunning()) {
            long delayMs = SystemClock.elapsedRealtime() - frameStartTimeMs;
            if (delayMs > INTERACTIVE_UPDATE_RATE_MS) {
                // This scenario occurs when drawing all of the components takes longer than an actual
                // frame. It may be helpful to log how many times this happens, so you can
                // fix it when it occurs.
                // In general, you don't want to redraw immediately, but on the next
                // appropriate frame (else block below).
                delayMs = 0;
            } else {
                // Sets the delay as close as possible to the intended framerate.
                // Note that the recommended interactive update rate is 1 frame per second.
                // However, if you want to include the sweeping hand gesture, set the
                // interactive update rate up to 30 frames per second.
                delayMs = INTERACTIVE_UPDATE_RATE_MS - delayMs;
            }
            updateTimeHandler.sendEmptyMessageDelayed(MSG_CODE_UPDATE_TIME, delayMs);
        }
    }
    

Untuk informasi lebih lanjut tentang menggambar pada instance Canvas, lihat Canvas dan Drawable.

Contoh WatchFace menyertakan tampilan jam lainnya yang dapat Anda referensikan sebagai contoh implementasi metode onDraw().