Lớp TextView là một đối tượng khung nhìn kết hợp khung nhìn với SurfaceTexture.
Kết xuất bằng OpenGL ES
Đối tượng TextView bao bọc một SurfaceTexture, phản hồi các lệnh gọi lại và thu được bộ đệm mới. Khi một TextView có được bộ đệm mới, một TextView sẽ đưa ra yêu cầu vô hiệu hóa chế độ xem và rút ra bằng cách sử dụng nội dung của bộ đệm mới nhất làm nguồn dữ liệu của nó, hiển thị ở bất kỳ đâu và theo cách mà trạng thái chế độ xem cho biết điều đó nên làm.
OpenGL ES (GLES) có thể hiển thị trên TextView bằng cách chuyển SurfaceTexture tới lệnh gọi tạo EGL, nhưng điều này gây ra sự cố. Khi GLES hiển thị trên một TextView, người tạo và người tiêu dùng BufferQueue ở trong cùng một luồng, điều này có thể khiến lệnh gọi hoán đổi bộ đệm bị đình trệ hoặc không thành công. Ví dụ: nếu nhà sản xuất gửi liên tiếp một số bộ đệm từ chuỗi giao diện người dùng, lệnh gọi hoán đổi bộ đệm EGL cần loại bỏ bộ đệm khỏi BufferQueue. Tuy nhiên, vì người tiêu dùng và nhà sản xuất nằm trên cùng một luồng nên sẽ không có bất kỳ bộ đệm nào và lệnh gọi trao đổi bị treo hoặc không thành công.
Để đảm bảo rằng việc hoán đổi bộ đệm không bị đình trệ, BufferQueue luôn cần có sẵn một bộ đệm để loại bỏ hàng đợi. Để thực hiện điều này, BufferQueue loại bỏ nội dung của bộ đệm đã thu được trước đó khi bộ đệm mới được xếp hàng đợi và đặt các hạn chế về số lượng bộ đệm tối thiểu và tối đa để ngăn người tiêu dùng sử dụng tất cả bộ đệm cùng một lúc.
Chọn SurfaceView hoặc TextView
SurfaceView và TextView có vai trò tương tự nhau và đều là công dân của hệ thống phân cấp chế độ xem. Tuy nhiên, SurfaceView và TextView có cách triển khai khác nhau. SurfaceView có cùng tham số với các chế độ xem khác, nhưng nội dung SurfaceView trong suốt khi được hiển thị.
TextView có khả năng xử lý alpha và xoay tốt hơn SurfaceView, nhưng SurfaceView có lợi thế về hiệu suất khi tổng hợp các thành phần UI được xếp lớp trên video. Khi máy khách kết xuất bằng SurfaceView, SurfaceView sẽ cung cấp cho máy khách một lớp thành phần riêng biệt. SurfaceFlinger tạo lớp riêng biệt dưới dạng lớp phủ phần cứng nếu được thiết bị hỗ trợ. Khi máy khách kết xuất bằng TextView, bộ công cụ UI sẽ tổng hợp nội dung của TextView vào hệ thống phân cấp chế độ xem bằng GPU. Các bản cập nhật nội dung có thể khiến các thành phần chế độ xem khác vẽ lại, ví dụ: nếu các chế độ xem khác được đặt ở trên cùng của một TextView. Sau khi hiển thị chế độ xem hoàn tất, SurfaceFlinger sẽ kết hợp lớp giao diện người dùng ứng dụng và tất cả các lớp khác để mỗi pixel hiển thị được kết hợp hai lần.
Nghiên cứu điển hình: Video Play của Grafika
Play Video của Grafika bao gồm một cặp trình phát video, một trình phát được triển khai bằng TextView và một trình phát được triển khai bằng SurfaceView. Phần giải mã video của hoạt động sẽ gửi các khung từ MediaCodec tới một bề mặt cho cả TextView và SurfaceView. Sự khác biệt lớn nhất giữa các lần triển khai là các bước cần thiết để trình bày tỷ lệ khung hình chính xác.
Việc mở rộng SurfaceView yêu cầu triển khai FrameLayout tùy chỉnh. WindowManager cần gửi vị trí cửa sổ mới và giá trị kích thước mới tới SurfaceFlinger. Việc chia tỷ lệ SurfaceTexture của TextView yêu cầu định cấu hình ma trận chuyển đổi với TextureView#setTransform()
.
Sau khi trình bày tỷ lệ khung hình chính xác, cả hai cách triển khai đều tuân theo cùng một mẫu. Khi SurfaceView/TextureView tạo bề mặt, mã ứng dụng sẽ cho phép phát lại. Khi người dùng nhấn vào phát , nó sẽ bắt đầu một chuỗi giải mã video, với bề mặt là mục tiêu đầu ra. Sau đó, mã ứng dụng không làm bất kỳ điều gì nữa—thành phần và hiển thị được xử lý bởi SurfaceFlinger (đối với SurfaceView) hoặc bởi TextView.
Nghiên cứu điển hình: Giải mã kép của Grafika
Giải mã kép của Grafika thể hiện thao tác của SurfaceTexture bên trong TextView.
Giải mã kép của Grafika sử dụng một cặp đối tượng TextView để hiển thị hai video phát cạnh nhau, mô phỏng ứng dụng hội nghị truyền hình. Khi hướng của màn hình thay đổi và hoạt động khởi động lại, bộ giải mã MediaCodec sẽ không dừng lại, mô phỏng việc phát lại luồng video theo thời gian thực. Để nâng cao hiệu quả, khách hàng nên giữ cho bề mặt luôn sống động. Bề mặt là một phần điều khiển cho giao diện của nhà sản xuất trong BufferQueue của SurfaceTexture. Bởi vì TextView quản lý SurfaceTexture nên máy khách cần giữ cho SurfaceTexture tồn tại để giữ cho bề mặt tồn tại.
Để giữ cho SurfaceTexture tồn tại, Double Decode của Grafika lấy các tham chiếu đến SurfaceTextures từ các đối tượng TextView và lưu chúng vào trường tĩnh. Sau đó, Double Decode của Grafika trả về false
từ TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed()
để ngăn chặn việc phá hủy SurfaceTexture. Sau đó, TextView chuyển SurfaceTexture tới onSurfaceTextureDestroyed()
có thể được duy trì trong suốt quá trình thay đổi cấu hình hoạt động mà khách hàng chuyển sang TextView mới thông qua setSurfaceTexture()
.
Các luồng riêng biệt điều khiển từng bộ giải mã video. Mediaserver gửi bộ đệm với đầu ra được giải mã tới SurfaceTextures, người tiêu dùng BufferQueue. Các đối tượng TextView thực hiện hiển thị và thực thi trên luồng giao diện người dùng.
Việc triển khai Giải mã kép của Grafika bằng SurfaceView khó hơn việc triển khai với TextView vì các đối tượng SurfaceView sẽ phá hủy các bề mặt trong quá trình thay đổi hướng. Ngoài ra, việc sử dụng các đối tượng SurfaceView sẽ thêm hai lớp, điều này không lý tưởng vì những hạn chế về số lượng lớp phủ có sẵn trên phần cứng.