Author:Mark L. Murphy
No description
Tags
Support Statistics
¥.00 ·
0times
Text Preview (First 20 pages)
Registered users can read the full content for free
Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.
Page
1
(This page has no text content)
Page
2
Elements of Kotlin Coroutines by Mark L. Murphy
Page
3
Elements of Kotlin Coroutines by Mark L. Murphy Copyright © 2019-2020 CommonsWare, LLC. All Rights Reserved. Printed in the United States of America. Printing History: June 2020 Version 0.2 The CommonsWare name and logo, “Busy Coder's Guide”, and related trade dress are trademarks of CommonsWare, LLC. All other trademarks referenced in this book are trademarks of their respective firms. The publisher and author(s) assume no responsibility for errors or omissions or for damages resulting from the use of the information contained herein.
Page
4
Table of Contents Headings formatted in bold-italic have changed since the last version. • Preface ◦ The Book’s Prerequisites ....................................................................... v ◦ About the Updates ..................................................................... vi ◦ What’s New in Version 0.2? ........................................................ vi ◦ Warescription ..................................................................................... vii ◦ Book Bug Bounty ............................................................................... viii ◦ Source Code and Its License ............................................................. viii ◦ Creative Commons and the Four-to-Free (42F) Guarantee ....... ix ◦ Acknowledgments ................................................................................ ix • Introducing Coroutines ◦ The Problems ......................................................................................... 1 ◦ What Would Be Slick ................................................................... 4 ◦ Actual Coroutine Syntax ............................................................ 5 ◦ Trying Out Coroutines In the Klassbook ................................... 5 ◦ Key Pieces of Coroutines ............................................................ 7 ◦ Suspending main() .............................................................................. 12 ◦ The Timeline of Events .............................................................. 13 ◦ Cheap, Compared to Threads .................................................... 15 ◦ The History of Coroutines .................................................................. 16 • Introducing Flows and Channels ◦ Life is But a Stream .............................................................................. 19 ◦ You’re Hot and You’re Cold ................................................................. 20 ◦ Flow Basics ........................................................................................... 20 ◦ Channel Basics ..................................................................................... 22 ◦ Hot and Cold Impacts ......................................................................... 23 • Exploring Builders and Scopes ◦ Builders Build Coroutines ................................................................... 25 ◦ The Basic Builders .................................................................... 25 ◦ Scope = Control .................................................................................... 29 ◦ Where Scopes Come From ........................................................ 30 • Choosing a Dispatcher ◦ Concurrency != Parallelism ................................................................. 35 ◦ Dispatchers: Controlling Where Coroutines Run .................... 36 ◦ launch() is Asynchronous ................................................................... 42 ◦ Some Context for Coroutines ............................................................ 44 i
Page
5
• Suspending Function Guidelines ◦ DO: Suspend Where You Need It ....................................................... 47 ◦ DON’T: Create Them “Just Because” ................................................. 48 ◦ DO: Track Which Functions Are Suspending .................................. 48 ◦ DON’T: Block ...................................................................................... 49 • Managing Jobs ◦ You Had One Job (Per Coroutine Builder) ......................................... 51 ◦ Contexts and Jobs ...................................................................... 51 ◦ Parents and Jobs .................................................................................. 52 ◦ Being Lazy on the Job ............................................................... 53 ◦ The State of Your Job ........................................................................... 55 ◦ Waiting on the Job to Change ............................................................. 55 ◦ Cancellation ............................................................................. 57 • Deferring Results • Structuring Concurrency • Working with Flows ◦ Getting a Flow ........................................................................... 79 ◦ Consuming a Flow .................................................................... 81 ◦ Flows and Dispatchers .............................................................. 84 ◦ Flows and Actions ..................................................................... 86 ◦ Flows and Other Operators ...................................................... 89 ◦ Flows and Exceptions ............................................................... 89 • Tuning Into Channels ◦ A Tale of Three Interfaces ......................................................... 95 ◦ Creating a Channel ................................................................... 95 ◦ Using a SendChannel ................................................................ 99 ◦ Consuming a ReceiveChannel .................................................. 99 ◦ Capacity Planning ................................................................... 103 ◦ Broadcasting Data ................................................................... 107 ◦ Operators ................................................................................. 110 • Opting Into StateFlow ◦ A Flow of States ......................................................................... 111 ◦ Creating and Consuming a StateFlow ..................................... 112 ◦ Decent Exposure ...................................................................... 113 ◦ Limitations .............................................................................. 113 ◦ Comparing to ConflatedBroadcastChannel ............................ 114 ◦ Comparing to LiveData ........................................................... 115 • Bridging to Callback APIs ◦ Coroutine Builders for Callbacks ............................................ 117 ◦ Flow Builders for Callbacks ..................................................... 121 • Creating Custom Scopes ii
Page
6
• Testing Coroutines • Integrating with RxJava • Applying Coroutines to Your UI ◦ A Quick Architecture Review ................................................... 133 ◦ The General Philosophy ........................................................... 136 ◦ Exposing Coroutines from a Repository ................................. 137 ◦ Consuming Coroutines in a ViewModel .................................. 141 ◦ Lifecycles and Coroutines ........................................................ 150 ◦ Immediate Dispatch ................................................................ 152 ◦ Bypassing LiveData ................................................................. 152 ◦ Events to Your UI ..................................................................... 159 ◦ Coroutines and Handler/Looper ............................................. 164 ◦ “But I Just Want an AsyncTask!” .............................................. 165 ◦ Coroutines and Views .............................................................. 169 • Java Interoperability • Appendix A: Hands-On Converting RxJava to Coroutines ◦ About the App ................................................................................... 179 ◦ Step #1: Reviewing What We Have .......................................... 180 ◦ Step #2: Deciding What to Change (and How) ............................... 196 ◦ Step #3: Adding a Coroutines Dependency .............................. 196 ◦ Step #4: Converting ObservationRemoteDataSource ..................... 197 ◦ Step #5: Altering ObservationDatabase .................................. 199 ◦ Step #6: Adjusting ObservationRepository ............................. 201 ◦ Step #7: Modifying MainMotor ............................................... 206 ◦ Step #8: Reviewing the Instrumented Tests .................................... 210 ◦ Step #9: Repair MainMotorTest ........................................................ 214 ◦ Step #14: Remove RxJava ................................................................... 222 iii
Page
7
(This page has no text content)
Page
8
Preface Thanks! First, thanks for your interest in Kotlin! Right now, Kotlin is Google’s primary language for Android app development, with Java slowly being relegated to second- tier status. Kotlin is popular outside of Android as well, whether you are building Web apps, desktop apps, or utility programs. Coroutines represent an important advancement in the Kotlin ecosystem, but it is a fairly complex topic. And, to that end… thanks for picking up this book! Here, you will learn what problems coroutines solve and how to implement them, in isolation and in the context of larger apps. The Book’s Prerequisites This book assumes that you have basic familiarity with Kotlin syntax, data types, and core constructs (e.g., lambda expressions). If you are new to Kotlin, please read Elements of Kotlin or another Kotlin book first, then return here. Don’t worry — we’ll wait for you. . . . OK! At this point, you’re an experienced Kotlin developer, ready to take the plunge into coroutines! v
Page
9
(and if you are still a bit new to Kotlin… that’s OK — we won’t tell anyone!) About the Updates Once this book reaches Version 1.0, it will be updated sporadically. JetBrains – the firm that created Kotlin — is fairly aggressive about improving the language. New minor versions of Kotlin (e.g., Kotlin 1.3) come out every year or two, and this book will be updated to reflect those changes. If you obtained this book through the Warescription, you will be able to download updates as they become available, for the duration of your subscription period. If you obtained this book through other channels… um, well, it’s still a really nice book! Each release has notations to show what is new or changed compared with the immediately preceding release: • The Table of Contents in the ebook formats (PDF, EPUB, MOBI/Kindle) shows sections with changes in bold-italic font • Those sections have changebars on the right to denote specific paragraphs that are new or modified And, there is the “What’s New” section, just below this paragraph. What’s New in Version 0.2? There are a few new chapters, covering: • Channels • StateFlow • Adapting callback-based APIs • Using coroutines in Android UIs In addition, there were many bug fixes and other updates to the existing material, to bring it more in line with version 1.3.6 of the coroutines libraries. PREFACE vi
Page
10
Warescription If you purchased the Warescription, read on! If you obtained this book from other channels, feel free to jump ahead. The Warescription entitles you, for the duration of your subscription, to digital editions of this book and its updates, in PDF, EPUB, and Kindle (MOBI/KF8) formats, plus the ability to read the book online at the Warescription Web site. You also have access to other books that CommonsWare publishes during that subscription period. Each subscriber gets personalized editions of all editions of each title. That way, your books are never out of date for long, and you can take advantage of new material as it is made available. However, you can only download the books while you have an active Warescription. There is a grace period after your Warescription ends: you can still download the book until the next book update comes out after your Warescription ends. After that, you can no longer download the book. Hence, please download your updates as they come out. You can find out when new releases of this book are available via: 1. The CommonsBlog 2. The CommonsWare Twitter feed 3. Opting into emails announcing each book release — log into the Warescription site and choose Configure from the nav bar 4. Just check back on the Warescription site every month or two Subscribers also have access to other benefits, including: • “Office hours” — online chats to help you get answers to your Android application development questions. You will find a calendar for these on your Warescription page. • A Stack Overflow “bump” service, to get additional attention for a question that you have posted there that does not have an adequate answer. • A discussion board for asking arbitrary questions about Android app development. PREFACE vii
Page
11
Book Bug Bounty Find a problem in the book? Let CommonsWare know! Be the first to report a unique concrete problem in the current edition, and CommonsWare will extend your Warescription by six months as a bounty for helping CommonsWare deliver a better product. By “concrete” problem, we mean things like: 1. Typographical errors 2. Sample applications that do not work as advertised, in the environment described in the book 3. Factual errors that cannot be open to interpretation By “unique”, we mean ones not yet reported. Be sure o check the book’s errata page, though, to see if your issue has already been reported. One coupon is given per email containing valid bug reports. We appreciate hearing about “softer” issues as well, such as: 1. Places where you think we are in error, but where we feel our interpretation is reasonable 2. Places where you think we could add sample applications, or expand upon the existing material 3. Samples that do not work due to “shifting sands” of the underlying environment (e.g., changed APIs with new releases of an SDK) However, those “softer” issues do not qualify for the formal bounty program. Questions about the bug bounty, or problems you wish to report for bounty consideration, should be sent to bounty@commonsware.com. Source Code and Its License The source code in this book is licensed under the Apache 2.0 License, in case you have the desire to reuse any of it. Copying source code directly from the book, in the PDF editions, works best with Adobe Reader, though it may also work with other PDF viewers. Some PDF viewers, PREFACE viii
Page
12
for reasons that remain unclear, foul up copying the source code to the clipboard when it is selected. Creative Commons and the Four-to-Free (42F) Guarantee Each CommonsWare book edition will be available for use under the Creative Commons Attribution-Noncommercial-ShareAlike 3.0 license as of the fourth anniversary of its publication date, or when 4,000 copies of the edition have been sold, whichever comes first. That means that, once four years have elapsed (perhaps sooner!), you can use this prose for non-commercial purposes. That is our Four-to- Free Guarantee to our readers and the broader community. For the purposes of this guarantee, new Warescriptions and renewals will be counted as sales of this edition, starting from the time the edition is published. This edition of this book will be available under the aforementioned Creative Commons license on 1 June 2024. Of course, watch the CommonsWare Web site, as this edition might be relicensed sooner based on sales. For more details on the Creative Commons Attribution-Noncommercial-ShareAlike 3.0 license, visit the Creative Commons Web site Note that future editions of this book will become free on later dates, each four years from the publication of that edition or based on sales of that specific edition. Releasing one edition under the Creative Commons license does not automatically release all editions under that license. Acknowledgments The author would like to thank JetBrains for their development of Kotlin. In particular, the author would like to thank Roman Elizarov and the rest of the coroutines development team. PREFACE ix
Page
13
(This page has no text content)
Page
14
The Rudiments of Coroutines
Page
15
(This page has no text content)
Page
16
Introducing Coroutines Kotlin is an ever-evolving language, with a steady stream of new releases. 2018 saw the release of Kotlin 1.3, and perhaps the pre-eminent feature in that release was the coroutines system. While coroutines do not change the language very much, they will change the development practices of Kotlin users substantially. For example, Google already is supporting coroutines in some of the Android Jetpack Kotlin extension libraries (“Android KTX”) and will expand upon those in the coming years. With all that in mind, you may be wondering what the fuss is all about. The Problems As experienced programmers know, software development is a series of problems occasionally interrupted by the release of working code. Many of those problems share common themes, and one long-standing theme in software development is “threading sucks”. Doing Work Asynchronously We often need to do work asynchronously, and frequently that implies the use of threads. For example, for the performance of a Web browser to be reasonable, we need to download assets (images, JavaScript files, etc.) in parallel across multiple threads. The bottleneck tends to be the network, so we parallelize a bunch of requests, queue up the remainder, and get whatever other work done that we can while we wait for 1
Page
17
the network to give us our data. Getting Results on a “Magic Thread” In many environments, one or more threads are special with respect to our background work: • In Android, JavaFx, and other GUI environments, updates to the UI are single-threaded, with a specific thread being responsible for those updates. Typically, we have to do any substantial work on background threads, so we do not tie up the UI thread and prevent it from updating the UI. However, in some cases, we also need to ensure that we only try to update the UI from the UI thread. So, while the long-running work might need to be done on a background thread, the UI effects of that work need to be done on the UI thread. • In Web app development, traditional HTTP verbs (e.g., GET, PUT, POST) are synchronous requests. The Web app forks a thread to respond to a request, and it is up to the code executing on that thread to construct and return the response. Even if that thread delegates work to some other thread (e.g., a processing thread pool) or process (e.g., a microservice), the Web request thread needs to block waiting for the results (or for some sort of timeout), so that thread can build the appropriate response. • And so on Doing So Without Going to Hell Software developers, as a group, are fond of mild profanity. In particular, we often describe things as being some form of “hell”, such as “DLL hell” for the problems of cross-software shared dependencies, as illustrated by DLL versioning in early versions of Microsoft Windows. Similarly, the term “callback hell” tends to be used in the area of asynchronous operations. Callbacks are simply objects representing chunks of code to be invoked when a certain condition occurs. In the case of asynchronous operations, the “certain condition” often is “when the operation completes, successfully or with an error”. In some languages, callbacks could be implemented as anonymous functions or lambda expressions, while in other languages they might need to be implementations of certain interfaces. INTRODUCING COROUTINES 2
Page
18
“Callback hell” occurs when you have lots of nested callbacks, such as this Java snippet: doSomething(new Something.Callback() { public void whenDone() { doTheNextThing(new NextThing.Callback() { public void onSuccess(List<String> stuff) { doSomethingElse(stuff, new SomethingElse.Callback() { public void janeStopThisCrazyThing(String value) { // TODO } }); } public void onError(Throwable t) { // TODO } }); } }); Here, doSomething(), doTheNextThing(), and doSomethingElse() might all arrange to do work on background threads, calling methods on the callbacks when that work completes. For cases where we need the callbacks to be invoked on some specific thread, such as a UI thread, we would need to provide some means for the background code to do that. For example, in Android, the typical low-level solution is to pass in a Looper; doSomething(Looper.getMainLooper(), new Something.Callback() { public void whenDone() { doTheNextThing(Looper.getMainLooper(), new NextThing.Callback() { public void onSuccess(List<String> stuff) { doSomethingElse(stuff, Looper.getMainLooper(), new SomethingElse.Callback() { public void janeStopThisCrazyThing(String value) { // TODO } }); } public void onError(Throwable t) { // TODO } }); } }); INTRODUCING COROUTINES 3
Page
19
The doSomething(), doTheNextThing(), and doSomethingElse() methods could then use that Looper (along with a Handler and some Message objects) to get the callback calls to be made on the thread tied to the Looper. This is a bit ugly, and it only gets worse as our scenarios get more complex. What Would Be Slick The ugliness comes from the challenges in following the execution flow through layers upon layers of callbacks. Ideally, the syntax for our code would not be inextricably tied to the threading model of our code. If doSomething(), doTheNextThing(), and doSomethingElse() could all do their work on the current thread, we would have something more like this: doSomething(); try { String result = doSomethingElse(doTheNextThing()); // TODO } catch (Throwable t) { // TODO } Or, in Kotlin syntax: doSomething() try { val result = doSomethingElse(doTheNextThing()) // TODO } catch (t: Throwable) { // TODO } What we want is to be able to do something like this, while still allowing those functions to do their work on other threads. INTRODUCING COROUTINES 4
Page
20
Actual Coroutine Syntax As it turns out, coroutines does just that. If doSomething(), doTheNextThing(), and doSomethingElse() all employ coroutines, our code invoking those functions could look something like this: someCoroutineScope.launch { doSomething() try { val result = doSomethingElse(doTheNextThing()) // TODO } catch (t: Throwable) { // TODO } } There is a lot of “plumbing” in Kotlin — both in the language and in libraries — that makes this simple syntax possible. We, as users of Kotlin, get to enjoy the simple syntax. Trying Out Coroutines In the Klassbook This book will have lots of sample snippets of Kotlin code demonstrating the use of coroutines. You may want to try running those yourself, with an eye towards changing the snippets and experimenting with the syntax, options, and so on. Many of the samples are in the Klassbook. The Klassbook is an online Kotlin sandbox, pre-populated with hundreds of different snippets (or “lessons”, as Klassbook terms them). Many of the Kotlin code snippets shown in this book are available in the Klassbook, with links below the snippet leading you to the specific Klassbook lesson. For example, here is a bit of Kotlin println("hello, world!") (from "Hello, World! (In a Function)" in the Klassbook) The “Hello, World! (In a Function)” link beneath the snippet leads you to the INTRODUCING COROUTINES 5
Comments 0
Loading comments...
Reply to Comment
Edit Comment