当前位置: 首页>移动开发>正文

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks

相关词汇

Continuation:协程内部概念
suspend:kotlin 编译器将使用callback重新suspend函数,suspend函数只能在协程中被调用
block:阻塞
modifier:修饰符
kotlin compiler:kotlin编译器,有空进步一步与java 编译器一起理解*****
dispatcher:调度器
computation :
concurrency :并发
memory leaks:内存泄露
coroutine scope:协程作用域将跟踪它创建的协程。可用用它cancel一个协程,获取失败通知。
lifecycle:生命周期
propagate :传播,scope中任务一个子任务失败是,用于传播通知其他子任务。

youtube视频链接

谷歌开发者关系团队的Android工程师Manuel Vivo介绍了Kotlin协程。请继续关注协程试图解决的问题,如何在Android中使用协程,如何测试它们,等等!

Kotlin Coroutines 101 - Android Conference Talks

文章

android上的kotlin协程--android开发者
Easy Coroutines in Android: viewModelScope

介绍

Manuel Vivo:Hi. I am Manuel Vivo . I'am an Android engineer in Developer Relations Team at Google.
This video is about an introduction to coroutines.will talk about the problems that coroutines are trying to solve,how to use coroutines in Andriod,how to test them,et cetera.

the First thing 简化异步编程

the first thing we want to talke about is ,what programs are they actually trying to solve?
They basically simplify asynchronous programming on Android.
So whenever we talk about asynchronous programming,we cannot forget about synchronous programming.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第1张
同步代码块

Here,we have the function loadData,which is going to display on the screen the reult of a networkRequest. And because this is synchronous ,it means that it will block the thread where this has been running on.
So imagine if we call loadData from the main UI thread,networkRequest will block their thread whenever it is waiting for the networkRequest to happen. And so in this case if the operating system is trying to call onDraw,that is not going to happen.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第2张
RNA奔溃

And therefore,the user will see a frozen UI and unresponsive application.
It will get unblocked whenever the networkRequest finishes and it calls show,as we can see.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第3张
同步网络请求

Let's see the definition of networkRequst here. networkRequest is just a function that returns data. And inside it,we have the blocking network request code. Blocking the main UI thread is someting that we shouldn't do in Android.
So how can we move this networkRequst to a different thread?
How can we make it asynchronous

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第4张
使用callback异步网络请求

A solution for this is using callbacks.
We have the same version of loadData. We're just going to make the networkRequest on a different thread.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第5张
在其他线程请求网络

Here ,as we can see,if we exeute this code,we can see that networkRequest will be called,and we will see later that the function networkRequest is going to be moving the execution of the networkRequest to a different thread.
And in this case,the main UI thread is free,and the operating system can call onDraw and refresh the screen as much as it wants. Whenever the networkRequest finishes, it will call this lambda, a callback,that is going to display the result of the networkRequest on the screen.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第6张
网络请求+callback

If we take a look at networkRequest,now it's just a function that doesn't return data anymore. Returns unit. And instead, it takes in a callback, a lambda that we call in this case onSuccess,with what to do after the networkRequest finishes. We can call DefaultSchedular.execute to move the execution of the networkRequest to a different thread. And after that finishes,then we can post to the main thread calling onSuccess.

So while callbacks might be ok solution for some use cases,it has some problem.

使用callback存在的一些问题

First thing is that now this is a simple function that it just makes another request and displays something on the screen.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第7张
2个网络请求嵌套

But now ,the logic can get complicated. We start adding a nesting networkRequest after the other one happens.
And now we can add more ,and more ,and more ,and more stuff.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第8张
很多层嵌套callback hell

This is what becomes the callback hell -- whenever there is a lot of indentation,erro propagation might be difficult. You have hard-coded posting to main thread whereever something happens,and you might not want to do that. It's complicated.

协程中suspend函数原理- 简单实现不同线程中的同步

What if we could have the best of both worlds--the simplicity of synchromous code with all the power from asynchronicity and moving things between threads?
And this is where curent thing come in.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第9张
suspend挂起函数

Here,we have the same function,loadData,written with coroutines. It might look a little bit suspicious, and you might think it will block the main UI thread,but it won't .
The only differentce that we have is this suspend modifier in the function definition.That's basically telling the kotlin compiler that this function needs to be executed with a coroutine.

So how doest it work?How can networkRequest no block the UI thread whenever it moves to a different thread?
Well,coroutines can suspend execution without blocking the thread. And that's going to happen whenever we move to execute something to a different thread. So that's what we call the suspension point. But also,whenever that networkRequest finishes ,then it will resume execution.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第10张
suspend-resume

So whenever the networkRequest is done with whatever it has to do,loadData can resume execution and continuing with the result of that networkRequest.
If you take a closer look,you will see that apart from netwrokRequest,the rest of the funcion is that what we used to have before as a callback.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第11张
suspend中与callback 类似的部分

So what is happening with the callback?
The kotlin complier will write that callback for you under the hood when the computation can suspend . And actually,coroutines call those callbacks a continuation. Continuation is just a generated callback interface with extra information in it.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第12张
suspend被编译成Continuation 回调

So how is the complier going to modify the function loadData?
Well, it will take the suspend modifer and replace it by a parameter of type continuation. And continuation form this state machine in which it will be executed depending if the function is suspended or not.

So we can say that when it starts ,the function start,it will start with a state 0. When it will suspend, it will chage state.When it will resume,it will be back to a different state,and then we will finish.This is what it's called continuation-passing style.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第13张
state-0
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第14张
state-1
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第15张
state-2
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第16张
state-3

And because it's quite a complicated topic,it is not going to be covered in this presentation. But as you can see,just a fancy way to say callbacks. So with coroutines ,computations can get suspended without blocking the thread,as we said before.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第17张
suspend-loadData

Back to our function loadData,we're going to see what networkRequest looks like,in this case. We will see that networkRequest is another suspend function ,but now it returns data as the synchronous version of it.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第18张
suspend-networkRequest
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第19张
suspend-networkRequest-by-withContext

How can networkRequest the execution to a different thread?
Well,it uses with context.With context is a suspend function from the coroutines that takes in a dispatcher as a parameter. Dispatcher is basically a way to say ,hey,I want to run this computation in this particular thread. And in this case,in IO.

And inside with context,we can have our blocking networkRequest code. It doesn't matter if it's blocking the IO thread. What is important is that it's not blocking the main UI thread.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第20张
Dispatchers类型

What other dispatchers do we have available?
We have Dispatchers.IO ,but also .Default and Dispatchers.Main.
IO is optimized to do network and disk cooperations. They use default for CPU-intensive tasks and main for UI code or non-blocking code that executes quite fast.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第21张
suspend-loadDate
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第22张
suspend-networkRequest

So here ,networkRequest,we can say that this is main safe. You can call networkRequest from the main UI thread,and it will be OK,because it will be in chart to move the execution to a different thread.

So now, we saw what problems coroutine are trained to solve,which is simply find asynchronous programming in Android.

理解协程-超级runnable

But what is a coroutine?
You can think a coroutine as a runable with super powers.
If you do think about it ,it is going to take a block of code,and it wil be able to run in a particular thread.
What I like about coroutines is that asynchronicity can be expressed in a sequential way. And that's going to be easier to read and understand. Also,it comes with other perks,such as exceptional handling and cancellation.
That is typically more difficult to do with other versions -- for example,callbacks.

Back to our funciton loadData. Imagine that we want to execute that whenever the user taps on a buttons.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第23张
onButtonClicked-call-loadData

For example,we can have this function onButtonClicked that will trigger loadData.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第24张
call-suspend-without-coroutine

But this is not going to compile,because suspend functions must be called inside a coroutine.

We don't know how to create coroutines yet. We will see that later.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第25张
launch启动suspend

But in a nutshell,you can see we can use lanch to trigger a coroutine. So imagine that this works. Here ,some problems may arise. For example,who can cancel the execution of that coroutineDoes it follow a particular lifecycleFor example ,if the [inaudible] is moving away from the screen,can you automatically canecl it Who is going to get the exception if that failsThere are the questions that a structured concurrency is trying to solve.
So structured concurrency is design pattern system in coroutines that tries to solve memory leaks.

And structured concurrency forces you to think about those questions whenever you are working with coroutines. And it does it by introducing this new concept,which is a scope --a coroutine scope.

coroutine scope is going to keep track of the coroutines it creates.It's going to give you the ability to cancel them. And it's going to be notified whenever a faiure happens.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第26张
onButtonClicked

So now,back to our funciton onButtonClicked,that will actually give another compiler error.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第27张
launch-without-scope

coroutine scope 协程作用域

That's because launch must be called within a scope. How can we create a coroutine scope?
A scope is just a simple variable that is really [inaudible] to create. It is not going to hold references to heavy objects. So whenever you want to control the lifecycle of a coroutine,you can create a coroutine scope.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第28张
launch-by-scope

So in this case,we can use this scope to trigger the computation. And that computation will follow,that coroutine will follow the lifecycle of that particular scope.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第29张
loadData-throw-exception

So in this case,if loadData throws an exception,and will handle it in some way.
Coroutines also create this hierarchy in whick the root of the hierarchy,it's going to be the scope,which is going to be the parent of the other coroutines that it creates.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第30张
kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第31张
call-scope.cancle

So in this case for example,whenever we don't need the scope anymore--for example ,if we are in a viewmodel, whenever we call onCleared,we can call a scope.cancel.
And cancelling a scope means that it will counsel all the children coroutines that it started,and it means as well that you cannot start more coroutines with that scope.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第32张
suspend-run-in-scope

So with our function loadData,we can see that this suspend funciton,because this will suspend,means that it has to be run inside a coroutine.It will run in a scope.And this is quite important.

If we take a step back and we think about synchronous code again,we can see that when a function returns,it means that it has completed all work. So imagine about the synchronous version of loadData. Even it block the thread ,it's OK,but it returned whenever it completed everything it had to do.

With coroutine ,it's kind of the same.When a suspend function returns ,means that it has completed all work. And this is a very nice contract to have in asynchronous operations.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第33张
scope-take-job

So now we're going to see how to handle exceptions. Scopes can also take a job. And a job is going to define the lifecycle of either the scope,and also the coroutines. And whenever we passing a job to a scope,that means that it's going to handle exceptions in a particular way.

When a child fails,it is going to provide the cancellation to other children. And when a failure is notified,the scope is going to cancel himself and propagate the exception up.

That means that in this case,whenever loadData fails, it will notify the scope that it failed.The scope will cancel the other children that it may have created defore it will cancel itself and will propagate the exception up.

In this case,because we are in a view model and there is nothing else in the hierarchy,it will make your application crash.But this might not be desired in every situation. For example ,here we are in a UI-related scope,and therefore,we might not want that behavior. So you can use the alternative ,which is SupervisorJob.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第34张
scope-take-SupervisorJob

And with a SupervisorJob,the failure of child ,it is no going to affect other children. And so when a failure is notified,the scope is not going to do anythine.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第35张

So in this case,loadData,if it throws an exception, the scope will say ,OK,I have these exceptions,but it's not going to cancel other children. Buf FYI,the exception can be propagated still, so you might have to try catch it.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第36张

TL;DR for a structured concurrency. When I suspend function returns,it means that it has completed all work. When the scope is canceled,it means that the children will be canceled too. when the coroutine errors out,the scope will get notified,and depending on the job ,it will behave in a way or another.

  • 注:TL;DR 不知道是什么,好像是与kotlin 本版有关

We're going to see how to create coroutine now. Before we saw that we can use launch to do that,but it is not the only way you can do it. You have to launch and async as well. We are going to compare them with the similarities and differences between these two defferent approaches.

As I said ,the first similarity is that they can create a new coroutine . They can start a computation where you can call suspend functions.But they create coroutines with a different purpose.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第37张

So launch is going to create a coroutine that is meant to be fired and forgotten.
So imagine that we have our loggingService where we can upload logs that happened in our application.

So we can use this scope.launch to trigger that computattion,and that's it. We don't care about it anymore. That's launch.

Asyn is goning to create a new coroutine that can return a a value.
Asyn将创建一个新的协程,它可以返回一个值。

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第38张
同步scope

So for example,we have this funciton,getUser,that takes in a userId as a parameter,and it returns a user object. Because we are in a suspend function,we don't have a scope avaible,so if we want to create a coroutine, we can use coroutineScope.

And inside here,we can fetch our user with our userService. And that computation can be happening in Dispatchers.IO, for example. So we have that. And that is going to --async is going to return a deferred object. And you can think of a deferred object as a futrue or a promise in Jave.

  • java 中使用futrue 或 promise

And with that future, or that deferred object, you can call await. And await will wait--actually, it will suspend execution of the coroutine until async has finished doing its computation,and it will return the value of that coroutine.

And this is what we return back to getUser.

Launch&Async

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第39张
launch& Async

Another similarity,as you saw ,is that both of them take a dispatcher. Where do you want to run that computation Also ,both of them are executed in scope.
Launch and async are extension functions on the scope. On coroutine scope,in this case.

And so in oder to create [inaudible], you need a scope. They are not a suspend functions so launch and async are the entry point to coroutines.
How you can create a coroutine so that you can call suspend functions ,but they are not suspend functions.
And they differ on the way they handle exceptions. ***
So launch is going to throw the exception as soon as it happens ,and async is going to hold on that exception until you call await.
we're going to see more of that in a second.

launch &async 处理异常

So how are you going to handle those exceptions?
Basically with a try-catch.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第40张
launch-handle-exception

Here in our version of launch we had before,because loggingService can throw an exception,you can grab it inside a try-catch,and that will handle the exception throw by the loggingService.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第41张
async-handle-exception

With async,it's a bit different. As we said,async is not going to throw the exception. Therefore ,you don't need to grab it inside the try-catch. You have to do it with await. Await can throw the exception that happened in the async block of code. Therefore,you have to wrap it inside try-catch. And there you will handle that exception.

协程处理繁忙任务如何cancellation

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第42张
频繁读取文件

Now we are going to move on to a different topic.
I have this coroutine on the screen that is called with launch, and it's going to happen in an IO thread.
So we have a for loop,which is going to read files from a list.
What happens if we call scope.cancel?
Is that going to cancel the execution of that coroutine or not?
Well,the fact it is not going to do that, becuase cancellation requires cooperation. Whenever you are doing something very expensive--in this case,we can spend a lot of time reading the files--you have to cooperate and make this cancelller work.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第43张
频繁操作+yield or ensueActive

If you think about it ,the coroutines of the thread is going to be really busy reading files,and it is not going to be listening for cancellation. So in this case ,you have to cooperate and check if the coroutine is active or not.

And you can do that bye checking for example,or calling ensureActive or yield. ***
Whenever the coroutine is cancelled and that function is called,then it will stop the execution of this coroutine.
So again,if you are doing a heavy computation,make sure that you check for cancellation.

如何确定使用suspend

We created a lot of functions throughout the presentation. And some of them were marked with suspend,some others weren't.
When do you actually have to mark something as suspend?
Well,this is easy.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第44张
如何确定使用suspend

Whenever it calls other suspend functions.So imagine our loadData function we had before. It is a suspend function. Why is that a suspend function?Because it calls networkRequest. That is also a suspend function. Why is networkRequest a suspend function Well ,because it called with context. And with context ,it is a suspend function that comes from the coroutines library. This is the reason why.

But now ,when don't you have to mark it as a suspendWell, whenever it doesn't call other suspend functions.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第45张
function-without-suspend

So onButtonClicked is just a function that triggers the coroutine. It calls launch. And because a launch is not as a suspend function, onButtonClicked doesn't need to be either.

So the tip is don't mark a function suspend unless you are forced to. And in this case, you either mark it as a suspend or you start the coroutine,as we did with onButtonClicked.

挂起函数、协程如何做单元测试

We're going to see how to test coroutines now.
So testing asynchronous code is quite difficult, because you want a deterministic behavior. You want the test to behave always in the same way. And we're going to see different use cases for the different ways that you have to do that.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第46张

The first use case, for those tests that don't trigger the execution of a new coroutine. So for example,let's say we want to test loadData. loadData,it is not calling async or launch. It's a suspend function. It's not triggering new coroutines. Even though it is moving to a different thread with context--that is what networkRequest is doing--it is not creating a new coroutine ,so we are OK here.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第47张
runBlocking-for-test

This is the first use case. You can test these using runBlocking.
runBlocking is a method from the coroutines library that is going to start a coroutine,and it's going to block the thread where it's been called until everything finishes, until the block of code finishes.

So in this case,we can create a viewModel instance called loadData ,and loadData is going to be executed synchronously.
And so we can make sure that the next line after loadData means that loadData has finished doing everything .
So now we can assert that show did something. That was quite easy,right

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第48张
second-case-test

The second use case is more complicated ,and it's for tests that trigger new coroutines. So for example,we have MyViewModel,and we want to test onButtonClicked. onButtonClicked is triggering a new computation,is triggering a new coroutine calling launch.

Can we use the same way as we did before runBlockingWell if we think about it ,whenever you call onButonClicked ,it is going to run a new coroutine. And that coroutine might be potentially running on a different thread. And so it is going to happen asynchronously. So onButtonClicked is going to call launch, and it's going to move on .It's going to end the function. So whenever you call assert,it might be happening that other coroutine is still running.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第49张

Therefore,it's not reliable. You cannot use it.
Another way is waiting for something to happen. So you imagine that you update some result somehow, and you wait for that to have a new value.
Either having a CountDownLatch,or using LiveDataTestUtil if you're using live data,or with Mockito await.
You have different ways to wait for something to be there.

But that's a code smell. That's because the test is not going to be running fast. Might take a couple of seconds for something to be there. And that's kind of a bad practice. The thing is that you might have to run it sequentially, as we did before with runBlocking. And how can you do that

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第50张

Well ,basically,we can do that by forcing the coroutine to run in a particular dispatcher.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第51张

And a good practice for this is injecting dispatchers.
So in this case for the viewModl, you can inject the dispatcher in the constructor, and then use the diapatcher to trigger the coroutine inside onButtonClicked.


kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第52张
viewModel构造方法输入dispatcher

And now we know our tests we can use a test coroutine dispatcher.
We create this test coroutine dispatcher instance that we are going to pass into the viewModel. So that coroutine is going to be executed in this test coroutine dispatcher. And in the test,instead of using runBlocking to wrap our test body within it ,we are going to use the function runBlocking Test for the testDispatcher.

That means that every coroutine running on that dispatcher is going to be executed simultaneously In that case,whenever we call onButtonClicked, it is going to execute that coroutine simultaneously.
That means that whenever onButtonClicked finishes,means that the coroutine has finished too. And now you can assert whenever show did something without having to wait for that to happen.

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第53张

But now ,imagine that onButtonClicked has to do something else before running the coroutine. How can we test that

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第54张

Well ,testCoroutineDispatcher comes with the nice functions to be able to post execution of coroutines ,and to resume them. So in this case ,we can call testDispatcher.pauseDispatcher to assert that something happened before the coroutine,and then call testDispatcher.resumeDispatcher to test what happened after the coroutine run.

So for testing,use runBlocking when test doesn't create new coroutine.
And as a good practice,inject dispatchers and use TestCocoutineDispatcher in tests whenever you want to test something that is going to trigger new coroutines.

总结

That 's going to be the end of the video.
We went throught a lot of stuff.So we said what problems coroutines are trying to solve in Android,which is simplifying asynchronous programming.
How we can move the execution to a different thread using dispatchers and withContext.
What coroutine is . Basically ,you can think of it as a runnable with super powers.
How coroutines work under the hood. The Kotlin compiler will rewrite the suspend functions to use callbacks.
The principles of structure concurrency that is going to avoid memory leaks and is going to force you to think of who is going to manage the lifecycle of that coroutine whenever you are working with them.
How to create coroutines ,and the differences between launch and async.
How to handle exceptions.
when to mark a function as a suspend,or not.
And testing coroutines ,and the usage of TestCoroutineDispatcher.

If you are interested in more thing about coroutines, I suggest that you go through the different Codelabs what we have available. We have two of them -- a basic Codelab and advanced Codelab that uses live data,coroutine builder, and more advanced topics. there is a video at Android Developer Summit 2019 where I give a talk with [inaudible].

And now ,for cancellation and exceptions,another video in KotlinConf 2019 with Florina Muntenescu.
Thank you for watching. Bye.

If you are more interested in testing coroutines ,

android studio 更新对StateFlow 支持

kotlin-笔记04-协程使用Kotlin Coroutines 101 - Android Conference Talks,第55张

For Kotlin apps that use coroutines, you can now use StateFlow objects as a data binding source to automatically notify the UI about changes in the data. Your data bindings will be lifecycle aware and will only be triggered when the UI is visible on the screen.
To use a StateFlow object with your binding class, you need to specify a lifecycle owner to define the scope of the StateFlow object, and in your layout, assign the properties and methods of your ViewModel component to the corresponding views using binding expressions, as shown in the following snippets:

class ViewModel() {
val username: StateFlow
}

<TextView
android:id="@+id/name"
android:text="@{viewmodel.username}" />

If you're in a Kotlin app that uses AndroidX, StateFlow support is automatically included in the functionality of data binding, including the coroutines dependencies.


https://www.xamrdz.com/mobile/42b1997295.html

相关文章: