iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Mobile Development

認真學 Compose - 對 Jetpack Compose 的問題與探索系列 第 26

D26 / 要怎麼放 Compose 進我的專案? - Compose View

今天大概會聊到的範圍

  • ComposeView

之前有介紹過 Compose 中的 AndroidView ,是一個可以在 Compose 中放入一般 Android View 。那如果我們要在一般的 Android 專案中放入 Compose 呢? 有幾個方法可以在原先 Android 的專案中加入 Compose

環境配置

之前有介紹過 Compose compiler 的運作機制,那些轉換都是透過 Kotlin 在 1.5 新增的 JVM IR compiler backend 。另外,Android Studio 也只有在 Arctic Fox 之後的版本才有支援 Compose、Android Build Tool 也需要在 7.0 以上:

// project-level build.gradle

buildscript {
    ...
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        ...
    }
}

// module-level build.gradle 

android {

    ... 

    kotlinOptions {
        jvmTarget = '1.8'
        useIR = true
    }

    buildFeatures {
        compose true
    }

    composeOptions {
        kotlinCompilerExtensionVersion compose_version
        kotlinCompilerVersion '1.5.10'
    }
    
    ...
}

準備就緒,開始導入 Compose 吧!先加入 Compose 相關的 library:

dependencies {
    // Integration with activities
    implementation 'androidx.activity:activity-compose:1.3.1'
    // Compose Material Design
    implementation 'androidx.compose.material:material:1.0.1'
    // Animations
    implementation 'androidx.compose.animation:animation:1.0.1'
    // Tooling support (Previews, etc.)
    implementation 'androidx.compose.ui:ui-tooling:1.0.1'
    // Integration with ViewModels
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
    // UI Tests
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.1'
}

Use setContent

如果整個頁面都可以使用 Compose 來建制的話,我們可以用我們學習 Compose 以來常常見到的好朋友 setContent function 來加入 Composable:

// 記得要加入 'androidx.activity:activity-compose:1.3.1'

class InteropActivity : AppCompatActivity() { // <-- 一般的 AppCompactActivity 就有繼承 ComponentActivity
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {    // <-- setContent 是 compose 在 ComponentActivity 身上加上的 extension fucntion    
            ComposeScreen()    // <--- 這裡就可以放 Composable 了
        }
    }
}

Use ComposeView

如果只有 Activity 中的某個部分想轉成 Compose,在 xml 中使用 ComposeView :

// in xml

<LinearLayout ...>

    ...

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/interopComposeView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    ...

</LinearLayout>


// in activity 

class InteropActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityInteropBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityInteropBinding.inflate(layoutInflater)        // <-- 這裡是用 ViewBinding。一般的 findViewById 也可以喔
        val root = binding.root


        binding.interopComposeView.setContent {
            // composable        // ComposeView 有 setContent  function 可以放入 composable
        }
        
        
        setContentView(root)
    }
}

Dispose Strategy

沒特別設定的話,ComposeView 會在 該 View detach window 時觸發 dispose。但是這可能不是期望的行為,例如在 Fragment 中我們可能希望跟著 Fragment 的 Lifecycle。

ComposeView 有 setViewCompositionStrategy function 可以使用,調整 dispose 的策略:

  • DisposeOnLifecycleDestroyed 可以讓 Compose 跟著 LifecycleOwner
  • DisposeOnViewTreeLifecycleDestroyed 則是在 LifecycleOwner 不方便取得時,直接透過 ViewTree 判斷適當的 dispose 時機

就這樣,把 ComposeView 當成一般的 View 放在 Android 內,再配合之前研究到的 AndroidView 就可以慢慢將計有專案 migrate 到 Compose 上囉!


Reference:


上一篇
D25 / 為什麼 State 改變會觸發 recomposition - State & Snapshot system
下一篇
D27 / 怎麼測試? - Testing Compose
系列文
認真學 Compose - 對 Jetpack Compose 的問題與探索30

尚未有邦友留言

立即登入留言