SurfaceView dan GLSurfaceView

UI framework aplikasi Android didasarkan pada hierarki objek yang dimulai dengan View . Semua elemen UI melalui serangkaian pengukuran dan proses tata letak yang menyesuaikannya ke dalam area persegi panjang. Kemudian, semua objek tampilan yang terlihat dirender ke permukaan yang disiapkan oleh WindowManager saat aplikasi dibawa ke latar depan. Thread UI aplikasi melakukan tata letak dan rendering ke buffer per frame.

Tampilan Permukaan

SurfaceView adalah komponen yang bisa Anda gunakan untuk menyematkan lapisan komposit tambahan dalam hierarki tampilan Anda. SurfaceView mengambil parameter tata letak yang sama dengan tampilan lainnya, sehingga dapat dimanipulasi seperti tampilan lainnya, namun konten SurfaceView transparan.

Saat Anda merender dengan sumber buffer eksternal, seperti konteks GL atau dekoder media, Anda perlu menyalin buffer dari sumber buffer untuk menampilkan buffer di layar. Menggunakan SurfaceView memungkinkan Anda melakukan itu.

Ketika komponen tampilan SurfaceView akan terlihat, kerangka kerja meminta SurfaceControl untuk meminta permukaan baru dari SurfaceFlinger. Untuk menerima panggilan balik saat permukaan dibuat atau dihancurkan, gunakan antarmuka SurfaceHolder . Secara default, permukaan yang baru dibuat ditempatkan di belakang permukaan UI aplikasi. Anda dapat mengganti urutan Z default untuk menempatkan permukaan baru di atas.

Merender dengan SurfaceView bermanfaat jika Anda perlu merender ke permukaan terpisah, seperti saat Anda merender dengan Camera API atau konteks OpenGL ES. Saat Anda merender dengan SurfaceView, SurfaceFlinger langsung membuat buffer ke layar. Tanpa SurfaceView, Anda perlu menggabungkan buffer ke permukaan di luar layar, yang kemudian dikomposisikan ke layar, sehingga rendering dengan SurfaceView menghilangkan pekerjaan tambahan. Setelah merender dengan SurfaceView, gunakan thread UI untuk berkoordinasi dengan siklus hidup aktivitas dan melakukan penyesuaian pada ukuran atau posisi tampilan jika diperlukan. Kemudian, Komposer Perangkat Keras memadukan UI aplikasi dan lapisan lainnya.

Permukaan baru adalah sisi produsen dari BufferQueue, yang konsumennya adalah lapisan SurfaceFlinger. Anda dapat memperbarui permukaan dengan mekanisme apa pun yang dapat memberi makan BufferQueue, seperti fungsi Canvas yang disediakan permukaan, memasang EGLSurface dan menggambar di permukaan dengan GLES, atau mengonfigurasi dekoder media untuk menulis permukaan.

SurfaceView dan siklus hidup aktivitas

Saat menggunakan SurfaceView, render permukaan dari thread selain thread UI utama.

Untuk aktivitas dengan SurfaceView, ada dua mesin status yang terpisah namun saling bergantung:

  • Aplikasi onCreate / onResume / onPause
  • Permukaan dibuat/diubah/dihancurkan

Saat aktivitas dimulai, Anda mendapatkan panggilan balik dalam urutan ini:

  1. onCreate()
  2. onResume()
  3. surfaceCreated()
  4. surfaceChanged()

Jika Anda mengklik kembali, Anda mendapatkan:

  1. onPause()
  2. surfaceDestroyed() (dipanggil tepat sebelum permukaannya hilang)

Jika Anda memutar layar, aktivitas tersebut dirobohkan dan dibuat ulang dan Anda mendapatkan siklus penuh. Anda dapat mengetahui bahwa ini adalah restart cepat dengan memeriksa isFinishing() . Aktivitas dapat dimulai/dihentikan dengan sangat cepat sehingga surfaceCreated() terjadi setelah onPause() .

Jika Anda mengetuk tombol daya untuk mengosongkan layar, Anda hanya mendapatkan onPause() tanpa surfaceDestroyed() . Permukaannya tetap aktif, dan rendering dapat dilanjutkan. Anda bisa terus mendapatkan acara Koreografer jika Anda terus memintanya. Jika Anda memiliki layar kunci yang memaksa orientasi berbeda, aktivitas Anda mungkin dimulai ulang saat perangkat tidak ditutup. Jika tidak, Anda bisa keluar dari layar kosong dengan permukaan yang sama seperti sebelumnya.

Masa pakai thread dapat dikaitkan dengan permukaan atau aktivitas, bergantung pada apa yang Anda inginkan terjadi saat layar menjadi kosong. Thread dapat memulai/berhenti pada saat Aktivitas mulai/berhenti atau pada pembuatan/penghancuran permukaan.

Membuat thread mulai/berhenti pada Aktivitas mulai/berhenti berfungsi baik dengan siklus hidup aplikasi. Anda memulai thread penyaji di onResume() dan menghentikannya di onStop() . Saat membuat dan mengonfigurasi thread, terkadang permukaannya sudah ada, terkadang tidak (misalnya, masih aktif setelah mengalihkan layar dengan tombol daya). Anda harus menunggu hingga permukaan dibuat sebelum menginisialisasi thread. Anda tidak dapat menginisialisasi dalam panggilan balik surfaceCreate() karena panggilan tersebut tidak akan diaktifkan lagi jika permukaan tidak dibuat ulang. Sebagai gantinya, buat kueri atau cache status permukaan, dan teruskan ke thread perender.

Membuat/menghancurkan thread mulai/berhenti di permukaan membuat/menghancurkan berfungsi dengan baik karena permukaan dan penyaji saling terkait secara logis. Anda memulai thread setelah permukaan dibuat, sehingga menghindari beberapa masalah komunikasi antar thread; dan pesan yang dibuat/diubah di permukaan hanya diteruskan. Untuk memastikan bahwa rendering berhenti saat layar menjadi kosong dan dilanjutkan kembali saat layar tidak kosong, beri tahu Koreografer untuk berhenti menjalankan callback penarikan bingkai. onResume() melanjutkan callback jika thread penyaji sedang berjalan. Namun, jika Anda menganimasikan berdasarkan waktu yang berlalu antar frame, mungkin ada kesenjangan besar sebelum peristiwa berikutnya tiba; menggunakan pesan jeda/lanjutkan yang eksplisit dapat mengatasi masalah ini.

Kedua opsi tersebut, apakah umur thread terkait dengan Aktivitas atau permukaan, berfokus pada cara thread perender dikonfigurasi dan apakah thread tersebut dieksekusi. Kekhawatiran terkait adalah mengekstraksi status dari thread ketika aktivitas dihentikan (dalam onStop() atau onSaveInstanceState() ); dalam kasus seperti ini, mengaitkan masa pakai thread dengan aktivitas akan berfungsi paling baik karena setelah thread penyaji digabungkan, status thread yang dirender dapat diakses tanpa primitif sinkronisasi.

Tampilan Permukaan GLS

Kelas GLSurfaceView menyediakan kelas pembantu untuk mengelola konteks EGL, komunikasi antar thread, dan interaksi dengan siklus hidup aktivitas. Anda tidak perlu menggunakan GLSurfaceView untuk menggunakan GLES.

Misalnya, GLSurfaceView membuat thread untuk merender dan mengonfigurasi konteks EGL di sana. Status dibersihkan secara otomatis saat aktivitas dijeda. Sebagian besar aplikasi tidak perlu mengetahui apa pun tentang EGL untuk menggunakan GLES dengan GLSurfaceView.

Dalam kebanyakan kasus, GLSurfaceView dapat mempermudah penggunaan GLES. Dalam beberapa situasi, hal ini dapat menghalangi.