安卓UDF单向数据流架构学习

UDF(Unidirectional Data Flow,单向数据流)是一种软件架构模式,广泛应用于现代前端和移动端开发中,尤其是在状态管理和用户界面处理方面。其核心思想是通过单一方向的数据流动来管理应用程序的状态和数据变化,确保数据的可预测性和可追溯性。UDF 的结构通常包括以下几个核心部分:

  • 意图(Intent)

    • 用户的交互或系统的事件被封装为“意图”,表示用户希望执行的操作或发生的事件。例如,按钮点击、页面加载等事件都可以看作是意图。
  • 操作(Action)

    • 意图被转换为操作,这些操作是对状态进行更改的具体行为。操作是纯粹的数据结构,描述了要做的事情,但不包含任何业务逻辑。
  • 状态(State)

    • 状态是应用程序当前的数据快照,表示 UI 应该展示的内容。状态在整个应用中是不可变的,唯一能够更改状态的方式是通过触发操作。
  • 处理器(Reducer)

    • 处理器负责接收操作并根据这些操作生成新的状态。处理器是纯函数,意味着它在不修改输入的情况下,返回新的状态对象。
  • 视图(View)

    • 视图观察状态的变化,并根据最新状态更新 UI。这确保了 UI 总是与当前状态同步。

UDF 的工作流程:

  1. 用户触发一个 意图(如点击按钮)。
  2. 该意图被发送到处理层,被转换为一个 操作
  3. 处理器 根据操作生成一个新的 状态
  4. 视图 根据新状态更新 UI。
  5. 任何后续的用户操作或系统事件会重复这个流程。

直接写一个小demo便于理解:

创建CountIntent.kt

这里使用sealed限制继承,只允许同一个文件内定义之类。

sealed class CountIntent {
    object Increment : CountIntent()
    object Decrement : CountIntent()
}

创建CountState.kt

data class CountState(
    var count:Int = 0
)

创建CountViewModel.kt

class CountViewModel : ViewModel() {

    // MutableStateFlow 是 StateFlow 的可变版本,用于内部更新状态
    private val _state = MutableStateFlow(CountState())

    // StateFlow 是一种冷流,适用于表示和管理单一可变的状态,总持有一个最新值,当有新值时会立即通知观察者
    val state: StateFlow<CountState> = _state

    // MutableSharedFlow 是 SharedFlow 的可变版本,用于在多个消费者之间共享数据流
    private val _intent = MutableSharedFlow<CountIntent>()

    // 初始化块,启动一个协程来收集意图并进行处理
    init {
        viewModelScope.launch {
            // 收集 _intent 中的值,并根据意图调用对应的方法
            _intent.collect { intent ->
                when (intent) {
                    is CountIntent.Increment -> increment()  // 处理增加计数的意图
                    is CountIntent.Decrement -> decrement()  // 处理减少计数的意图
                }
            }
        }
    }
    // 公有方法,供外部调用,用于发送意图
    fun sendIntent(intent: CountIntent) {
        viewModelScope.launch {
            _intent.emit(intent)  // 发射意图到 _intent 流
        }
    }

    // 私有方法,增加计数并更新状态
    private suspend fun increment() {
        _state.emit(CountState(_state.value.count + 1))  // 增加计数并发射新的状态
    }

    // 私有方法,减少计数并更新状态
    private suspend fun decrement() {
        _state.emit(CountState(_state.value.count - 1))  // 减少计数并发射新的状态
    }
}

最后在MainActivity.kt中调用就好了。这样一个UDF+MVI的架构demo就完成了

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel:CountViewModel
    private lateinit var binding:ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        binding=ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        viewModel= ViewModelProvider(this).get(CountViewModel::class.java)

        lifecycleScope.launch {
            viewModel.state.collect{state->
                binding.text.text=state.count.toString()
            }
        }
    }
    fun addOnClick(view : View){
        viewModel.sendIntent(CountIntent.Increment)
    }
    fun subOnClick(view : View){
        viewModel.sendIntent(CountIntent.Decrement)
    }
}

还是把activity_main.xml文件贴出来吧:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:onClick="addOnClick"
        android:layout_marginTop="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+1" />

    <Button
        android:onClick="subOnClick"
        android:layout_marginTop="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="-1" />

</LinearLayout>

其实总体还是比较简单的,这样架构主要体现分层,提高代码可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大菠萝‍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值