返回

Jetpack Compose 优化:将函数移出可组合项

Android

Jetpack Compose 代码优化:将函数从可组合项中移出

导言

Jetpack Compose 是 Android 开发人员用于构建用户界面的一个强大工具。通过声明性 UI 和状态管理分离,Compose 提升了代码的可读性、可维护性和可重用性。然而,为了进一步优化我们的代码,我们可以将函数从可组合项中移出,以增强其清晰度和灵活性。

将函数移出的原因

将函数从可组合项中移出有以下好处:

  • 增强可读性: 通过将与 UI 相关的逻辑和非 UI 相关的逻辑分开,我们可以创建更易于阅读和理解的代码。
  • 提高可维护性: 将函数移出可组合项后,它们可以独立修改和重用,从而降低了维护代码的复杂性。
  • 增加可重用性: 将函数移动到共享位置,例如视图模型或帮助器类,可以提高不同可组合项之间的可重用性。

将函数移出的选项

将函数从可组合项中移出的主要选项有:

  • 视图模型: 视图模型是一种与 UI 逻辑交互但与 UI 视图无关的类。它是存储数据和处理业务逻辑的理想场所。
  • 帮助器类: 帮助器类用于封装通用或可重用代码,包括函数。它们允许我们组织和模块化代码,使其更易于理解和维护。
  • 帮助器函数: 帮助器函数是包含在单独文件中的独立函数,可执行特定任务。它们类似于帮助器类,但没有显式类结构。

选择合适的选项

在选择将函数移出的选项时,需要考虑以下因素:

  • 代码的可重用性: 函数是否在多个可组合项中使用?如果是,则将它们移动到帮助器类或帮助器函数中可能是更好的选择。
  • 代码的复杂性: 函数是否复杂或涉及大量业务逻辑?如果是,则将它们移动到视图模型中可能更合适。
  • 代码的可维护性: 将函数移出可组合项是否会提高代码的可读性和可维护性?如果是,则值得进行迁移。

实战示例

让我们通过一个实际示例来说明如何将函数从可组合项中移出。假设我们有一个名为 AccountSummary 的可组合项,它包含用于生成 UI 属性名称的逻辑:

@Composable
fun AccountSummary(account: Account) {
    val titleList = listOf(
        SummaryTitle.UNFUNDED,
        SummaryTitle.FUNDED,
        SummaryTitle.BUDGET,
        SummaryTitle.SPENT,
        SummaryTitle.REMAINING,
        SummaryTitle.UNASSIGNED,
        SummaryTitle.TOTAL,
        SummaryTitle.INCOME,
        SummaryTitle.WAITING,
        SummaryTitle.RECEIVED
    )

    val list = titleList.map { title ->
        title.title to when (title) {
            SummaryTitle.UNFUNDED -> (account.total - account.funded)
            SummaryTitle.FUNDED -> account.funded
            SummaryTitle.BUDGET -> account.total
            SummaryTitle.SPENT -> account.spentFunds
            SummaryTitle.REMAINING -> account.remainingFunds
            SummaryTitle.UNASSIGNED -> account.unassignedFunds
            SummaryTitle.TOTAL -> account.total
            SummaryTitle.INCOME -> account.total
            SummaryTitle.WAITING -> account.total - account.funded
            SummaryTitle.RECEIVED -> account.funded
            else -> throw IllegalArgumentException("Unknown title, failed to process: $title")
        }
    }
}

在此示例中,fetchKeyValuePairsgetListOfRowItems 函数特定于 AccountSummary 可组合项,并且不太可能在其他可组合项中重用。因此,将它们移到一个名为 AccountSummaryHelper 的帮助器类中是一个明智的选择。

优化后的代码:

class AccountSummaryHelper {

    fun fetchKeyValuePairs(titleList: List<SummaryTitle>, obj: Account): List<Pair<String, Serializable>> {
        return titleList.map { title ->
            title.title to when (title) {
                SummaryTitle.UNFUNDED -> (obj.total - obj.funded)
                SummaryTitle.FUNDED -> obj.funded
                SummaryTitle.BUDGET -> obj.total
                SummaryTitle.SPENT -> obj.spentFunds
                SummaryTitle.REMAINING -> obj.remainingFunds
                SummaryTitle.UNASSIGNED -> obj.unassignedFunds
                SummaryTitle.TOTAL -> obj.total
                SummaryTitle.INCOME -> obj.total
                SummaryTitle.WAITING -> obj.total - obj.funded
                SummaryTitle.RECEIVED -> obj.funded
                else -> throw IllegalArgumentException("Unknown title, failed to process: $title")
            }
        }
    }

    fun getListOfRowItems(account: Account): List<Pair<String, Serializable>> {
        val incomeDisplayProperties = listOf(
            SummaryTitle.WAITING,
            SummaryTitle.RECEIVED,
            SummaryTitle.INCOME,
            SummaryTitle.UNASSIGNED,
        )

        val fixedExpenseDisplayProperties = listOf(
            SummaryTitle.UNFUNDED,
            SummaryTitle.FUNDED,
            SummaryTitle.BUDGET,
            SummaryTitle.UNASSIGNED,
            SummaryTitle.SPENT,
            SummaryTitle.REMAINING,
        )

        val emergencyFundDisplayProperties = listOf(
            SummaryTitle.UNFUNDED,
            SummaryTitle.FUNDED,
            SummaryTitle.BUDGET,
            SummaryTitle.UNASSIGNED
        )

        val loansDisplayProperties = listOf(
            SummaryTitle.TOTAL,
            SummaryTitle.UNASSIGNED
        )

        val savingsDisplayProperties = listOf(
            SummaryTitle.TOTAL,
            SummaryTitle.UNASSIGNED
        )

        return when (account.name) {
            AccountType.INCOME -> fetchKeyValuePairs(incomeDisplayProperties, account)
            AccountType.FIXED_EXPENSES -> fetchKeyValuePairs(fixedExpenseDisplayProperties, account)
            AccountType.LOANS -> fetchKeyValuePairs(loansDisplayProperties, account)
            AccountType.SAVINGS -> fetchKeyValuePairs(savingsDisplayProperties, account)
            AccountType.EMERGENCY_FUND -> fetchKeyValuePairs(emergencyFundDisplayProperties, account)
            else -> throw IllegalArgumentException("Unknown AccountType: ${account.name}")
        }
    }
}

现在,我们可以将这些函数从 AccountSummary 可组合项中移除,并使用 AccountSummaryHelper 类访问它们:

@Composable
fun AccountSummary(account: Account, modifier: Modifier = Modifier) {
    val helper = AccountSummaryHelper()
    val list = helper.getListOfRowItems(account)

    Column { ...//UI code }
}

结论

通过将函数从 Jetpack Compose 可组合项中移出,我们可以显著提高代码的可读性、可维护性和可重用性。通过选择合适的选项,例如视图模型、帮助器类或帮助器函数,我们可以根据具体需求对代码进行优化。这样做不仅可以提高代码质量,还可以简化未来的维护和扩展。

常见问题解答

1. 我应该将所有函数都从可组合项中移出吗?
不,只有当函数具有以下特征时才应该将其移出:可重用性低、复杂或会影响可维护性。

2. 将函数移出可组合项后,是否会影响性能?
在大多数情况下,不会。然而,在某些情况下,例如将大量数据操作移出可组合项,可能会导致轻微的性能下降。

3. 我可以使用哪些工具来帮助我标识要移动的函数?
Android Studio 中的代码分析工具可以帮助你识别复杂或重复的函数。

4. 将函数移出可组合项会破坏 Jetpack Compose 的响应式特性吗?
只要正确地管理状态,将函数移出可组合项就不会破坏响应式特性。

5. 我应该将函数移到哪个位置?
根据具体情况,可以将函数移到视图模型、帮助器类或帮助器函数中。