Technology sharing

kotlin Flow Study Guide (3) Final Chapter

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Praefatio

Primi duo articuli introducuntur quid sit fluxus, quomodo uti, et progressiones operator cognata. Sequens articulus maxime introducit usum Flu in actualibus inceptis.

Vita cycle flow

Priusquam ipsam applicationem missionum Fluminis inducamus, primum timorem exempla recenseamus quae in primo articulo Fluminis introducta sunt.

class MainViewModel : ViewModel() {

val timeFlow = flow {
    var time = 0
    while (true) {
        emit(time)
        delay(1000)
        time++
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Deinde in activitate, data rivulo prius definito accipimus.

lifecycleOwner.lifecycleScope.launch {
    viewModel.timeFlow.collect { time ->
        times = time
        Log.d("ddup", "update UI $times")
    }
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Curram ipsum videre effectum;

flow1.gif

Animadvertisti cum App switches ad curriculum, stipes adhuc excudendi. Hoc non est perditio opum.

lifecycleOwner.lifecycleScope.launchWhenStarted {
     viewModel.timeFlow.collect { time ->
         times = time
         Log.d("ddup", "update UI $times")
     }
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Methodum incipiendi coroutine ab launch ad launch cumStarted transeamus, et iterum curramus ad effectum;

flow2.gif

Videre possumus cum button domestica deprimatur et in curriculum redierit, stipes non amplius impressus est. Videri potest mutationem effectum percepisse, sed remissum est rivum? vultu:

flow3.gif

Commutatio ad fabricam, videre potest ab 0 occurro non incipere, re vera receptionem non excludit, modo intermittit in curriculo notitias receptas API relicta est. Google RepeatOnLifecycle magis suadetur sed non habet quaestionem de notitia antiqua retinendi in pipelino.
Conemur mutare codicem respondentem:

lifecycleOwner.lifecycleScope.launch {
    lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.timeFlow.collect { time ->
            times = time
            Log.d("ddup", "update UI $times")
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Re- currunt ad effectum;

flow4.gif

Videre possumus quod, cum ex curriculo in fabricam mutando, notitia ab 0 iterum incipit, id significat, cum in curriculo mutando, fluere opus destruit et omnia notitia originalia purgata sunt.

Fluere utimur et per repeatOnLifecycle securitatem programmatis nostri melius curare possumus.

StateFlow notificata locum tenet LiveData

Praemissae introductiones omnia exempla fluunt frigidi.
Adhuc utens exemplo priore timentis, quid fiet si velum inter screen horizontali et verticali mutandum est?

flow5.gif

Videre possumus post commutationes inter screens horizontales et verticales, Activitas recreetur. Ab 0. Saepius computatis, inter tegumenta horizontalia et verticalia commutare volumus. Hoc tempore speramus paginae statum immutatum manere, saltem intra certum temporis spatium influunt et tentant;

val hotFlow =
    timeFlow.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(5000),
        0
    )
    
    ```
lifecycleOwner.lifecycleScope.launch {
    lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.hotFlow.collect { time ->
            times = time
            Log.d("ddup", "update UI $times")
        }
    }
}
```
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Hic tres parametros in stateIn intendunt. Primus unus est scopus coroutine, secundus est maximum tempus efficax ad conservandum statum suum laborantem modulus valorem initialem.

Re- currere ad effectum;

flow6.gif

Hic videre possumus stipes impressos post commutationes inter tegumenta horizontalia et verticalia.
Supra induximus quomodo frigidum fluxum in fluxum calidum mutare.

private val _stateFlow = MutableStateFlow(0)
val stateFlow = _stateFlow.asStateFlow()

fun startTimer() {
    val timer = Timer()
    timer.scheduleAtFixedRate(object :TimerTask() {
        override fun run() {
            _stateFlow.value += 1
        }

    },0,1000)
}

```

viewModel.startTimer()

lifecycleOwner.lifecycleScope.launch {
    lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.stateFlow.collect { time ->
            times = time
            Log.d("ddup", "update UI $times")
        }
    }
}
```
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

StatuFlow fluxum calidum definimus, tum statumFlow valorem per modum startTimer() immutare, similem LiveData setData LiveData Observa modum monitoris notitiarum mutationum.
Inspice effectum ipsum currens:

flow7.gif

Hic usum fundamentalem StateFlow induximus, et nunc SharedFlow introducemus.

SharedFlow

Intellegere SharedFlow, primum cognoscimus notionem rerum glutinosam. Litteram, cum observator subscribit datorum principium, si notitia principii iam habet novissimam datam, tunc notitia statim ad aspectum impelletur. Ex praedictis explicationibus iudicantes, LiveData convenit huic visco notae. Simplicem demom scribamus ut verificetur:


class MainViewModel : ViewModel() {

private val _clickCountFlow = MutableStateFlow(0)

val clickCountFlow = _clickCountFlow.asStateFlow()

fun increaseClickCount() {
    _clickCountFlow.value += 1
}
}
//MainActivity
```
val tv = findViewById<TextView>(R.id.tv_content)
val btn = findViewById<Button>(R.id.btn)
btn.setOnClickListener {
    viewModel.increaseClickCount()
}

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.clickCountFlow.collect { time ->
            tv.text = time.toString()
            Log.d("ddup", "update UI $time")
        }
    }
}
```

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

Primum definimus clickCountFlow in MainViewModel, deinde in Activity, clickCountFlow datam mutare strepitando Puga pyga, et tunc accipimus clickCountFlow et notitias in textu ostende.
Inspice effectum currentem:

flow8.gif

Videre possumus, cum inter screens horizontales et verticales mutando, Actio recreatur et clickCountFlow re- colligitur. Notitia adhuc incipit a 4 priore, significans StateFlow lentum esse aliud exemplum spectamus. Simulamus missionem strepita-ad-login, deprime puga login ut aperi et aperi in:

//MainViewModel
    private val _loginFlow = MutableStateFlow("")
    val loginFlow = _loginFlow.asStateFlow()
    fun startLogin() {
        // Handle login logic here.
        _loginFlow.value = "Login Success"
    }
//MainActivity

```
val tv = findViewById<TextView>(R.id.tv_content)
val btn = findViewById<Button>(R.id.btn)
btn.setOnClickListener {
    viewModel.startLogin()
}

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.loginFlow.collect {
            if (it.isNotBlank()) {
                Toast.makeText(this@MainActivity2, it, Toast.LENGTH_LONG).show()
            }
        }
    }
}
```
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

Praecedens signum re vera crepitum login simulat, ac deinde submittit ut login quod proficiat.

flow9.gif

Nonne vides, postquam inter screens horizontales et verticales mutando, prospere login promptum pops renascentes? Non perreximus processum re-loginum SharedFlow et experior:

    private val _loginFlow = MutableSharedFlow<String>()

    val loginFlow = _loginFlow.asSharedFlow()
    fun startLogin() {
        // Handle login logic here.
        viewModelScope.launch {
            _loginFlow.emit("Login Success")
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Mutavimus StateFlow ad SharedFlow. Videre possumus quod SharedFlow valorem valorem non requirit.

flow10.gif

Hic videre possumus hanc quaestionem viscum non accidere cum usus SharedFlow.

    public fun <T> MutableSharedFlow(
        // 每个新的订阅者订阅时收到的回放的数目,默认0
        replay: Int = 0,

       // 除了replay数目之外,缓存的容量,默认0
        extraBufferCapacity: Int = 0,

      // 缓存区溢出时的策略,默认为挂起。只有当至少有一个订阅者时,onBufferOverflow才会生效。当无订阅者时,只有最近replay数目的值会保存,并且onBufferOverflow无效。
        onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Plures sunt usus SharedFlow exspectationis omnium ad cognoscendum, sed hic singula non ingrediar.

Alia communi applicatione missionum

Antea fundamentales frigidos fluxus ad calidum fluxum induximus, sicut ad communem usum et ad missiones StatusFlow et SharedFlow applicabiles. Deinceps plura exempla practica inspiciemus ad alias applicationes communes missionum fluunt.

Manubrium complexum, tempus consumens logicam

Solet facere logicam quandam complexam temporis consumens, eam in sub-filo processire, et deinde ad filum principale ut UI ostendat. Fluxus etiam stamina mutandi sustinet, et fluere possunt operationes priorem in sub-filo respondentem ad dispensandum ponere .
Nos legere loci effectum deducendiAssetssub indicemperson.jsonfile et parse eum;jsonTabulae contenta:

{
  "name": "ddup",
  "age": 101,
  "interest": "earn money..."
}
  • 1
  • 2
  • 3
  • 4
  • 5

Tum parse tabella:

fun getAssetJsonInfo(context: Context, fileName: String): String {
    val strBuilder = StringBuilder()
    var input: InputStream? = null
    var inputReader: InputStreamReader? = null
    var reader: BufferedReader? = null
    try {
        input = context.assets.open(fileName, AssetManager.ACCESS_BUFFER)
        inputReader = InputStreamReader(input, StandardCharsets.UTF_8)
        reader = BufferedReader(inputReader)
        var line: String?
        while ((reader.readLine().also { line = it }) != null) {
            strBuilder.append(line)
        }
    } catch (ex: Exception) {
        ex.printStackTrace()
    } finally {
        try {
            input?.close()
            inputReader?.close()
            reader?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return strBuilder.toString()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

Fluunt files legit:

/**
 * 通过Flow方式,获取本地文件
 */
private fun getFileInfo() {
    lifecycleScope.launch {
        flow {
            //解析本地json文件,并生成对应字符串
            val configStr = getAssetJsonInfo(this@MainActivity2, "person.json")
            //最后将得到的实体类发送到下游
            emit(configStr)
        }
            .map { json ->
                Gson().fromJson(json, PersonModel::class.java) //通过Gson将字符串转为实体类
            }
            .flowOn(Dispatchers.IO) //在flowOn之上的所有操作都是在IO线程中进行的
            .onStart { Log.d("ddup", "onStart") }
            .filterNotNull()
            .onCompletion { Log.d("ddup", "onCompletion") }
            .catch { ex -> Log.d("ddup", "catch:${ex.message}") }
            .collect {
                Log.d("ddup", "collect parse result:$it")
            }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Final print log:

2024-07-09 22:00:34.006 12251-12251 ddup com.ddup.flowtest D onStart 2024-07-09 22:00:34.018 12251-12251 ddup com.ddup.flowtest D collect parse result:PersonModel(name=ddup, age=101, interest=earn money...) 2024-07-09 22:00:34.019 12251-12251 ddup com.ddup.flowtest D onCompletion

Interface petitiones clientelas

Saepe occurrant petitiones interfaces quae pendent ex eventibus alterius petitionis, quae vocantur evolutae petitiones.

lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        //将两个flow串联起来 先搜索目的地,然后到达目的地
        viewModel.getTokenFlows()
            .flatMapConcat {
                //第二个flow依赖第一个的结果
                viewModel.getUserFlows(it)
            }.collect {
                tv.text = it ?: "error"
            }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Miscere notitia ex pluribus interfaces

Quae est missio coniungendi notitias ex pluribus interfaces? Exempli gratia, rogamus multiplices interfaces, et deinde iungunt eventus ut uniformiter exhibeant vel utantur rogantibus parametris pro alio instrumento.
Primum est singillatim petendi et deinde confundendi;
Secundum genus est simul petere, et tunc omnes petitiones confunduntur.
Patet, alterum effectum efficaciorem esse.

//分别请求电费、水费、网费,Flow之间是并行关系
suspend fun requestElectricCost(): Flow<SpendModel> =
    flow {
        delay(500)
        emit(SpendModel("电费", 10f, 500))
    }.flowOn(Dispatchers.IO)

suspend fun requestWaterCost(): Flow<SpendModel> =
    flow {
        delay(1000)
        emit(SpendModel("水费", 20f, 1000))
    }.flowOn(Dispatchers.IO)

suspend fun requestInternetCost(): Flow<SpendModel> =
    flow {
        delay(2000)
        emit(SpendModel("网费", 30f, 2000))
    }.flowOn(Dispatchers.IO)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Primum petitiones retis in ViewModel simulavit ac definivit, deinde petitiones immiscuit:

lifecycleScope.launch {
    val electricFlow = viewModel.requestElectricCost()
    val waterFlow = viewModel.requestWaterCost()
    val internetFlow = viewModel.requestInternetCost()

    val builder = StringBuilder()
    var totalCost = 0f
    val startTime = System.currentTimeMillis()
    //NOTE:注意这里可以多个zip操作符来合并Flow,且多个Flow之间是并行关系
    electricFlow.zip(waterFlow) { electric, water ->
        totalCost = electric.cost + water.cost
        builder.append("${electric.info()},n").append("${water.info()},n")
    }.zip(internetFlow) { two, internet ->
        totalCost += internet.cost
        two.append(internet.info()).append(",nn总花费:$totalCost")
    }.collect {
        tv.text = it.append(",总耗时:${System.currentTimeMillis() - startTime} ms")
        Log.d(
            "ddup",
            "${it.append(",总耗时:${System.currentTimeMillis() - startTime} ms")}"
        )
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

operatio effectus;
flow11.png
Videmus totum tempus consumptum esse basically idem ac longissimum tempus postulationis.

Cautiones per O

MultiplexFlownon in unolifecycleScope.launchIte intuscollect{}Quia intrantescollect{}Aequivalent ansa infinita, codicis altera linea numquam exsequatur; si vis scribere alifecycleScope.launch{}Ite intro, rursus ab intus vertere poteslaunch{}Sub- coroutine fit.
Error exemplum:

lifecycleScope.launch {
    flow1
        .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
        .collect {}

   flow2
        .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
        .collect {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Recta via est ad scribendum;

lifecycleScope.launch {
    launch {
       flow1
            .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
            .collect {}
    }

    launch {
      flow2
            .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
            .collect {}
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Summatim

Ex cyclo vitae fluere, rectam usum habitudinem fluxus ad vitandam vastitatem facultatum introduximus, ad conversionem frigidum ordinarium in fluxum calidum influentem, ad StateFlow reponendo LiveData, eiusque problema glutinosum, ac deinde problema per glutinosum solvitur. SharedFlow, et deinde ad missiones communes Applicationes, ac denique cautiones utendi Fluxus, basically maxime tegunt lineamenta et applicationes missionum Fluminum.
Creare non facile est, sed molestum estAmo, colligere, adhortari
Reference article
Kotlin O programmatio reciprocus, StateFlow et SharedFlow

Kotlin |