Hướng dẫn

Những yếu tố khác cần cân nhắc về hiệu suất

Đọc trong 8 phút
3 Tác giả
Ben Weiss, Breana Tate, Jossi Wolf

Hãy bình tĩnh và để chúng tôi hướng dẫn bạn tìm hiểu thêm thông tin về hiệu suất.

Chào mừng bạn đến với ngày thứ 3 của Tuần lễ tiêu điểm về hiệu suất. Hôm nay, chúng tôi sẽ tiếp tục chia sẻ thông tin chi tiết và hướng dẫn về những khía cạnh quan trọng của hiệu suất ứng dụng. Chúng ta sẽ đề cập đến tính năng Tối ưu hoá theo hướng dẫn của hồ sơ, các điểm cải thiện hiệu suất trong Jetpack Compose và những điều cần cân nhắc khi làm việc ở chế độ nền. Hãy cùng bắt đầu ngay nhé.

Tối ưu hoá theo cấu hình

Hồ sơ cơ sở và Hồ sơ khởi động là nền tảng để cải thiện hiệu suất khởi động và thời gian chạy của ứng dụng Android. Đây là một phần của nhóm các hoạt động tối ưu hoá hiệu suất có tên là Tối ưu hoá theo cấu hình.

Khi một ứng dụng được đóng gói, dexer d8 sẽ lấy các lớp và phương thức rồi điền vào các tệp classes.dex của ứng dụng. Khi người dùng mở ứng dụng, các tệp dex này sẽ được tải lần lượt cho đến khi ứng dụng có thể khởi động. Bằng cách cung cấp một Hồ sơ khởi động, bạn cho d8 biết những lớp và phương thức cần đóng gói trong các tệp classes.dex đầu tiên. Cấu trúc này cho phép ứng dụng tải ít tệp hơn, từ đó cải thiện tốc độ khởi động.

Hồ sơ cơ sở giúp di chuyển hiệu quả các bước biên dịch Trong khi thực thi (JIT) ra khỏi thiết bị của người dùng và vào máy của nhà phát triển. Mã được biên dịch Trước thời gian chạy (AOT) đã được chứng minh là giúp giảm thời gian khởi động và các vấn đề về kết xuất.

Trello và Hồ sơ cơ sở

Chúng tôi đã hỏi các kỹ sư của ứng dụng Trello về mức độ ảnh hưởng của Hồ sơ cơ sở đến hiệu suất của ứng dụng. Sau khi áp dụng Cấu hình cơ sở cho hành trình chính của người dùng, Trello nhận thấy thời gian khởi động ứng dụng giảm đáng kể 25%.

image.png

Trello đã có thể cải thiện thời gian khởi động ứng dụng của họ thêm 25 % bằng cách sử dụng hồ sơ cơ sở.

Hồ sơ cơ sở tại Meta

Ngoài ra, các kỹ sư tại Meta gần đây đã xuất bản một bài viết về cách họ tăng tốc ứng dụng Android bằng Hồ sơ cơ sở.

image.png

Trên các ứng dụng của Meta, các nhóm đã nhận thấy nhiều chỉ số quan trọng được cải thiện tới 40 % sau khi áp dụng Hồ sơ cơ sở.

Những điểm cải tiến về kỹ thuật như thế này cũng giúp bạn cải thiện mức độ hài lòng của người dùng và sự thành công của doanh nghiệp. Việc chia sẻ thông tin này với chủ sở hữu sản phẩm, Giám đốc công nghệ và những người đưa ra quyết định cũng có thể giúp cải thiện hiệu suất của ứng dụng.

Bắt đầu sử dụng Hồ sơ cơ sở

Để tạo Hồ sơ cơ sở hoặc Hồ sơ khởi động, bạn viết một kiểm thử macrobenchmark để thực thi ứng dụng. Trong quá trình kiểm thử, dữ liệu hồ sơ sẽ được thu thập và dùng trong quá trình biên dịch ứng dụng. Các kiểm thử được viết bằng UiAutomator API mới mà chúng ta sẽ đề cập vào ngày mai.

Việc viết một phép đo điểm chuẩn như thế này rất đơn giản và bạn có thể xem toàn bộ mẫu trên GitHub.

  @Test

fun profileGenerator() {

    rule.collect(

        packageName = TARGET_PACKAGE,

        maxIterations = 15,

        stableIterations = 3,

        includeInStartupProfile = true

    ) {

        uiAutomator {

            startApp(TARGET_PACKAGE)

        }

    }


}

Những yếu tố nên cân nhắc

Bắt đầu bằng cách viết một Hồ sơ cơ sở kiểm thử macrobenchmark và một Hồ sơ khởi động cho đường dẫn mà người dùng truy cập nhiều nhất. Điều này có nghĩa là điểm truy cập chính mà người dùng truy cập vào ứng dụng của bạn, thường là sau khi họ đăng nhập. Sau đó, hãy tiếp tục viết thêm các trường hợp kiểm thử để nắm bắt một bức tranh đầy đủ hơn chỉ dành cho Hồ sơ cơ sở. Bạn không cần phải bao gồm mọi thứ trong Hồ sơ cơ sở. Tuân thủ các đường dẫn được sử dụng nhiều nhất và đo lường hiệu suất trong thực tế. Chúng tôi sẽ nói thêm về vấn đề này trong bài đăng ngày mai.

Bắt đầu sử dụng tính năng Tối ưu hoá theo hướng dẫn của hồ sơ

Để tìm hiểu cách Hồ sơ cơ sở hoạt động, hãy xem video này trong Hội nghị dành cho nhà phát triển Android:

Ngoài ra, hãy xem tập Android Build Time về tính năng Tối ưu hoá dựa trên hiệu năng để tìm hiểu thêm: 

Chúng tôi cũng có hướng dẫn chi tiết về Hồ sơ cơ sởHồ sơ khởi động để bạn đọc thêm.

Cải thiện hiệu suất của Jetpack Compose

Khung giao diện người dùng cho Android đã cho thấy hiệu quả của việc đầu tư vào hiệu suất của nhóm kỹ thuật. Kể từ phiên bản 1.9 của Jetpack Compose, hiện tượng giật khi cuộn đã giảm xuống còn 0,2 % trong một thử nghiệm nội bộ về hiệu suất cuộn dài. 

jankyFrames.png

Những điểm cải tiến này có được là nhờ một số tính năng có trong các bản phát hành gần đây nhất.

Khoảng thời gian lưu vào bộ nhớ đệm có thể tuỳ chỉnh

Theo mặc định, bố cục trì hoãn chỉ tạo một mục trước theo hướng cuộn và sau khi một mục nào đó cuộn ra khỏi màn hình, mục đó sẽ bị loại bỏ. Giờ đây, bạn có thể tuỳ chỉnh số lượng mục cần giữ lại thông qua một phần kích thước khung hiển thị hoặc dp. Điều này giúp ứng dụng của bạn thực hiện nhiều công việc hơn ngay từ đầu và sau khi bật thành phần có thể tạm dừng giữa các khung hình, ứng dụng sẽ sử dụng thời gian có sẵn một cách hiệu quả hơn.

Để bắt đầu sử dụng các cửa sổ bộ nhớ đệm có thể tuỳ chỉnh, hãy tạo thực thể cho LazyLayoutCacheWindow và truyền thực thể đó vào danh sách hoặc lưới tải từng phần. Đo lường hiệu suất của ứng dụng bằng cách sử dụng nhiều kích thước cửa sổ bộ nhớ đệm, chẳng hạn như 50% khung nhìn. Giá trị tối ưu sẽ phụ thuộc vào cấu trúc nội dung và kích thước của mặt hàng.

  val dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)

val state = rememberLazyListState(cacheWindow = dpCacheWindow)

LazyColumn(state = state) {

    // column contents

}

Thành phần có thể tạm dừng

Tính năng này cho phép tạm dừng các thành phần và chia công việc của chúng thành nhiều khung hình. Các API này đã có trong phiên bản 1.9 và hiện được dùng theo mặc định trong phiên bản 1.10 để tìm nạp trước bố cục lười biếng. Bạn sẽ thấy lợi ích rõ rệt nhất khi sử dụng các mục phức tạp có thời gian kết hợp lâu hơn. 

image.png

Các hoạt động tối ưu hoá hiệu suất Compose khác

Trong các phiên bản 1.9 và 1.10 của Compose, nhóm cũng đã thực hiện một số điểm tối ưu hoá ít rõ ràng hơn.

Một số API sử dụng coroutine về bản chất đã được cải thiện. Ví dụ: khi sử dụng DraggableClickable, nhà phát triển sẽ thấy thời gian phản hồi nhanh hơn và số lượng phân bổ được cải thiện.

Việc tối ưu hoá tính năng theo dõi hình chữ nhật bố cục đã cải thiện hiệu suất của các đối tượng sửa đổi như onVisibilityChanged()onLayoutRectChanged(). Điều này giúp tăng tốc giai đoạn bố cục, ngay cả khi bạn không sử dụng các API này một cách rõ ràng.

Một điểm cải thiện hiệu suất khác là sử dụng các giá trị được lưu vào bộ nhớ đệm khi quan sát các vị trí thông qua onPlaced().

Tìm nạp trước văn bản ở chế độ nền

Kể từ phiên bản 1.9, Compose bổ sung khả năng tìm nạp trước văn bản trên một luồng nền. Điều này cho phép bạn làm nóng trước bộ nhớ đệm để bố cục văn bản nhanh hơn và phù hợp với hiệu suất kết xuất ứng dụng. Trong quá trình bố trí, văn bản phải được truyền vào khung Android, nơi một bộ nhớ đệm từ được điền sẵn. Theo mặc định, thao tác này chạy trên luồng Ui. Việc chuyển hoạt động tìm nạp trước và điền vào bộ nhớ đệm từ vào một luồng ở chế độ nền có thể tăng tốc bố cục, đặc biệt là đối với các văn bản dài hơn. Để tìm nạp trước trên một luồng nền, bạn có thể truyền một trình thực thi tuỳ chỉnh đến bất kỳ thành phần kết hợp nào đang sử dụng BasicText ở chế độ nền bằng cách truyền LocalBackgroundTextMeasurementExecutor đến CompositionLocalProvider như sau.

  val defaultTextMeasurementExecutor = Executors.newSingleThreadExecutor()

CompositionLocalProvider(

    LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor

) {

    BasicText("Some text that should be measured on a background thread!")


}

Tuỳ thuộc vào văn bản, điều này có thể giúp tăng hiệu suất hiển thị văn bản. Để đảm bảo rằng việc này giúp cải thiện hiệu suất kết xuất của ứng dụng, hãy đo điểm chuẩn và so sánh kết quả.

Những điểm cần cân nhắc về hiệu suất của công việc ở chế độ nền

Tác vụ ở chế độ nền là một phần thiết yếu của nhiều ứng dụng. Bạn có thể đang sử dụng các thư viện như WorkManager hoặc JobScheduler để thực hiện các tác vụ như:

  • Tải các sự kiện phân tích lên theo định kỳ
  • Đồng bộ hoá dữ liệu giữa một dịch vụ phụ trợ và cơ sở dữ liệu
  • Xử lý nội dung nghe nhìn (tức là đổi kích thước hoặc nén hình ảnh)

Một thách thức chính khi thực hiện những tác vụ này là cân bằng hiệu suất và hiệu quả sử dụng năng lượng. WorkManager giúp bạn đạt được sự cân bằng này. API này được thiết kế để tiết kiệm pin và cho phép hoãn công việc đến một khung thời gian thực thi tối ưu, chịu ảnh hưởng của một số yếu tố, bao gồm cả các điều kiện ràng buộc mà bạn chỉ định hoặc các điều kiện ràng buộc do hệ thống áp đặt. 

Tuy nhiên, WorkManager không phải là một giải pháp chung cho tất cả. Android cũng có một số API được tối ưu hoá về mức tiêu thụ điện năng và được thiết kế riêng cho một số Hành trình phổ biến của người dùng cốt lõi (CUJ).  

Tham khảo trang đích về Hoạt động trong nền để xem danh sách một số hoạt động trong số này,  bao gồm cả việc cập nhật tiện ích và lấy vị trí ở chế độ nền.

Công cụ gỡ lỗi cục bộ cho Tác vụ trong nền: Các trường hợp phổ biến

Để gỡ lỗi Background Work và hiểu lý do khiến một tác vụ có thể bị trễ hoặc không thành công, bạn cần biết cách hệ thống đã lên lịch cho các tác vụ của bạn. 

Để hỗ trợ việc này, WorkManager có một số công cụ liên quan giúp bạn gỡ lỗi cục bộ và tối ưu hoá hiệu suất (một số công cụ này cũng hoạt động với JobScheduler)! Sau đây là một số trường hợp phổ biến mà bạn có thể gặp phải khi sử dụng WorkManager, cùng với phần giải thích về các công cụ bạn có thể dùng để gỡ lỗi.

Gỡ lỗi lý do công việc theo lịch không thực thi

Công việc theo lịch bị trì hoãn hoặc không thực hiện được có thể là do một số yếu tố, bao gồm cả việc không đáp ứng các quy tắc ràng buộc đã chỉ định hoặc các quy tắc ràng buộc đã được hệ thống áp đặt

Bước đầu tiên trong quá trình điều tra lý do khiến công việc theo lịch không chạy là xác nhận rằng công việc đã được lên lịch thành công.  Sau khi xác nhận trạng thái lập lịch, hãy xác định xem có bất kỳ điều kiện ràng buộc hoặc điều kiện tiên quyết nào chưa được đáp ứng khiến công việc không thực hiện được hay không.

Có một số công cụ để gỡ lỗi trong trường hợp này.

Công cụ kiểm tra tác vụ trong nền

Công cụ kiểm tra tác vụ trong nền là một công cụ mạnh mẽ được tích hợp trực tiếp vào Android Studio. Công cụ này cung cấp thông tin trực quan về tất cả các tác vụ WorkManager và trạng thái liên quan (Đang chạy, Đã xếp hàng, Không thành công, Thành công). 

Để gỡ lỗi lý do khiến công việc theo lịch không thực thi bằng Công cụ kiểm tra tác vụ trong nền, hãy tham khảo(các) trạng thái Công việc được liệt kê. Trạng thái "Đã xếp hàng" cho biết Work của bạn đã được lên lịch nhưng vẫn đang chờ chạy.

Lợi ích: Ngoài việc cung cấp một cách dễ dàng để xem tất cả các việc cần làm, công cụ này đặc biệt hữu ích nếu bạn có công việc theo chuỗi. Công cụ kiểm tra tác vụ trong nền cung cấp chế độ xem biểu đồ có thể trực quan hoá xem liệu một tác vụ trước đó không thành công có thể đã ảnh hưởng đến việc thực thi tác vụ sau hay không.

image.png

Chế độ xem danh sách của Công cụ kiểm tra tác vụ trong nền

image.png

Chế độ xem biểu đồ của Công cụ kiểm tra tác vụ trong nền

adb shell dumpsys jobscheduler

Lệnh này trả về danh sách tất cả các tác vụ JobScheduler đang hoạt động (bao gồm cả Worker của WorkManager) cùng với các quy tắc ràng buộc được chỉ định và các quy tắc ràng buộc do hệ thống áp đặt. API này cũng trả về nhật ký công việc. 

Hãy sử dụng chế độ này nếu bạn muốn xem công việc đã lên lịch và các ràng buộc liên quan theo một cách khác. Đối với các phiên bản WorkManager trước WorkManager 2.10.0, adb shell dumpsys jobscheduler sẽ trả về danh sách Worker có tên này:

  [package name]/androidx.work.impl.background.systemjob.SystemJobService

Nếu ứng dụng của bạn có nhiều worker, thì việc cập nhật lên WorkManager 2.10.0 sẽ cho phép bạn xem tên Worker và dễ dàng phân biệt giữa các worker:

  #WorkerName#@[package name]/androidx.work.impl.background.systemjob.SystemJobService

Lợi ích:  Lệnh này hữu ích khi bạn muốn biết có ràng buộc nào do hệ thống áp đặt  hay không. Bạn không thể xác định được điều này bằng Công cụ kiểm tra tác vụ trong nền. Ví dụ: thao tác này sẽ trả về nhóm chờ của ứng dụng, có thể ảnh hưởng đến khoảng thời gian hoàn thành công việc đã lên lịch.

Bật tính năng ghi nhật ký gỡ lỗi

Bạn có thể bật tính năng ghi nhật ký tuỳ chỉnh để xem nhật ký chi tiết của WorkManager. Nhật ký này sẽ có WM— được đính kèm. 

Lợi ích: Nhờ đó, bạn có thể biết được thời điểm công việc được lên lịch, các giới hạn được đáp ứng và các sự kiện trong vòng đời. Bạn có thể tham khảo những nhật ký này trong khi phát triển ứng dụng.

WorkInfo.StopReason

Nếu nhận thấy hiệu suất không dự đoán được với một worker cụ thể, bạn có thể theo dõi theo chương trình lý do worker của bạn bị dừng trong lần chạy trước đó bằng WorkInfo.getStopReason

Bạn nên định cấu hình ứng dụng để theo dõi WorkInfo bằng cách sử dụng getWorkInfoByIdFlow nhằm xác định xem công việc của bạn có bị ảnh hưởng bởi các hạn chế về hoạt động trong nền, các điều kiện ràng buộc, tình trạng hết thời gian chờ thường xuyên hay thậm chí là bị người dùng dừng hay không.

Lợi ích: Bạn có thể sử dụng WorkInfo.StopReason để thu thập dữ liệu trường về hiệu suất của nhân viên.

Gỡ lỗi thời lượng khoá chế độ thức cao do WorkManager phân bổ và được Android vitals gắn cờ

Android vitals có một chỉ số khoá chế độ thức một phần quá mức, giúp làm nổi bật những khoá chế độ thức góp phần làm tiêu hao pin. Bạn có thể ngạc nhiên khi biết rằng WorkManager thu thập khoá đánh thức để thực thi các tác vụ và nếu khoá đánh thức vượt quá ngưỡng do Google Play đặt, thì điều này có thể ảnh hưởng đến khả năng hiển thị của ứng dụng. Làm cách nào để gỡ lỗi khi có quá nhiều thời gian khoá chế độ thức được quy cho công việc của bạn? Bạn có thể sử dụng các công cụ sau.

Trang tổng quan Android vitals

Trước tiên, hãy xác nhận trong trang tổng quan Android vitals về lỗi khoá chế độ thức quá mức rằng thời lượng khoá chế độ thức cao do WorkManager chứ không phải do báo thức hoặc khoá chế độ thức khác. Bạn có thể sử dụng tài liệu Xác định các khoá đánh thức do các API khác tạo để biết những khoá đánh thức nào được giữ do WorkManager. 

Perfetto

Perfetto là một công cụ dùng để phân tích dấu vết hệ thống. Khi sử dụng công cụ này để gỡ lỗi WorkManager, bạn có thể xem phần "Trạng thái thiết bị" để biết thời điểm bắt đầu, thời gian chạy và mức tiêu thụ điện năng của công việc. 

Trong mục "Trạng thái thiết bị: Tác vụ", bạn có thể thấy mọi worker đã được thực thi và các khoá đánh thức liên kết.

deviceState.png

Phần Trạng thái thiết bị trong Perfetto, cho thấy quá trình thực thi CleanupWorker và BlurWorker.

Tài nguyên

Tham khảo trang Gỡ lỗi WorkManager để biết thông tin tổng quan về các phương thức gỡ lỗi có sẵn cho những trường hợp khác mà bạn có thể gặp phải.

Để tự mình thử một số phương thức này và tìm hiểu thêm về cách gỡ lỗi WorkManager, hãy xem lớp học lập trình WorkManager và hoạt động kiểm thử nâng cao.

Các bước tiếp theo

Hôm nay, chúng ta đã đi xa hơn việc rút gọn mã và khám phá cách Android Runtime và Jetpack Compose thực sự kết xuất ứng dụng của bạn. Cho dù đó là biên dịch trước các đường dẫn quan trọng bằng Hồ sơ cơ sở hay làm mượt các trạng thái cuộn bằng các tính năng mới của Compose 1.9 và 1.10, những công cụ này đều tập trung vào cảm giác khi dùng ứng dụng của bạn. Chúng ta cũng đã tìm hiểu sâu về các phương pháp hay nhất để gỡ lỗi hoạt động ở chế độ nền.

Hỏi Android

Vào thứ Sáu, chúng tôi sẽ tổ chức một buổi Hỏi và đáp trực tiếp về hiệu suất. Hãy đặt câu hỏi ngay bây giờ bằng hashtag #AskAndroid để các chuyên gia giải đáp cho bạn.

Thách thức

Chúng tôi đã yêu cầu bạn bật R8 vào thứ Hai. Hôm nay, chúng tôi yêu cầu bạn tạo một Hồ sơ cơ sở cho ứng dụng của mình.

Với Android Studio Otter, trình hướng dẫn mô-đun Trình tạo hồ sơ cơ sở giúp bạn thực hiện việc này dễ dàng hơn bao giờ hết. Chọn hành trình trọng yếu nhất của người dùng (ngay cả khi đó chỉ là quá trình khởi động và đăng nhập vào ứng dụng) rồi tạo một hồ sơ.

Sau khi có được, hãy chạy Macrobenchmark để so sánh CompilationMode.None với CompilationMode.Partial.

Chia sẻ những điểm cải thiện về thời gian khởi động trên mạng xã hội bằng hashtag #optimizationEnabled.

Đừng quên xem vào ngày mai

Bạn đã rút gọn ứng dụng bằng R8 và tối ưu hoá thời gian chạy bằng tính năng Tối ưu hoá theo hướng dẫn của hồ sơ. Nhưng làm cách nào để bạn chứng minh những thành công này cho các bên liên quan? Và làm cách nào để bạn phát hiện các lỗi hồi quy trước khi chúng xuất hiện trong bản phát hành chính thức?

Hãy tham gia cùng chúng tôi vào ngày mai trong Ngày 4: Hướng dẫn về việc đánh giá hiệu suất. Tại đây, chúng tôi sẽ trình bày cụ thể cách đo lường mức độ thành công của bạn, từ dữ liệu thực địa trong Play Vitals cho đến tính năng theo dõi cục bộ chuyên sâu bằng Perfetto.

Tác giả:

Tiếp tục đọc