[Android] Làm thế nào để cải thiện hiệu năng của app trên những thiết bị sử dụng CPU "không được mạnh cho lắm" với Jetpack Compose ?

[Android] Làm thế nào để cải thiện hiệu năng của app trên những thiết bị sử dụng CPU "không được mạnh cho lắm" với Jetpack Compose ?

Hello anh em, sau những ngày tháng chống chọi với covid và đối tác thì hôm nay mình lại ngoi lên viết bài phục vụ anh em đây :D.

Trường hợp của bài viết ngày hôm nay khá đặc biệt, thiết bị chạy Android với chip của nhà sản xuất đến từ Trung Quốc chuyên sử dụng cho các hệ thống IoT, smart-home... vì thế nên hiệu năng cũng không thể nào so sánh được với những ông lớn như snapdragon hay mediatek được. Và nhiệm vụ của chúng ta là phải cải thiện được hiệu năng cho thiết bị đó :(

Trước khi vào vấn đề chính, mời anh em đọc qua các khái niệm
Jetpack compose
Recomposed
Restartable
Skippable

Jetpack Compose navigation

Khi nào thì hiệu năng của app bị giảm?

Bất cứ khi nào thực hiện thao tác chuyển màn hình, call api, query local db ... sẽ khiến app rơi vào tình trạng giật lag trông thấy rõ rệt, và nguyên nhân gây ra điều đó là do cơ chế navigation của jetpack compose.
Theo tài liệu của google viết:

As you navigate between composables, the content of the NavHost is automatically recomposed.

Vậy là đã rõ, mỗi khi ta thực hiện di chuyển màn hình thì các view (composable) bên trong chúng đều phải render lại, và điều này thực sự không dễ dàng gì với các máy có CPU còi cả.
Một lần nữa vấn đề này lại khiến mình tốn rất nhiều não, câu hỏi đặt ra ở đây là làm thế nào để có thể lưu được state mỗi khi chuyển màn hình trong compose?

Fragment xuất hiện như 1 vị thần :(

Chắc có lẽ các anh em dev android đã biết, fragment của android có cơ chế ẩn và lưu state. Tới đây mình sử dụng 1 chút trick để bọc các màn hình compose lại vào bên trong của fragment và sử dụng nó để navigate mà khiến chúng không bị giật lag nữa.

class HomeFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(
            R.layout.fragment_sale,
            container,
            false
        ).apply {
            findViewById<ComposeView>(R.id.composeView).setContent {
                HomeScreen()
            }
        }
    }
}

với xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.compose.ui.platform.ComposeView
            android:id="@+id/composeView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Và khi sử dụng chúng để di chuyển màn hình thì chỉ cần gọi:

private fun showFragment(currentFragment: Fragment, targetFragment: Fragment) {
        supportFragmentManager
            .beginTransaction()
            .hide(currentFragment)
            .show(targetFragment)
            .commit()
    }

Vậy là từ giờ trở đi không cần phải lo app bị giật nữa rồi <3

Ref:
https://github.com/tylerbwong/stack/
https://medium.com/geekculture/7-jetpack-compose-projects-to-become-a-better-android-developer-282879cb197f
Chúc ae áp dụng thành công vào các dự án thực tế <3.