Видео. Architecture Components. Solving the Lifecycle Problem. Перевод субтитров.
Теги: Java, Android, Архитектура, Video, Youtube, Translate, Architecture Components, Философия
Перевод английских субтитров на русские из видео Architecture Components: Solving the Lifecycle Problem. Начало 09.09.2017, конец - .09.2017. All rights reserved.
Смотри другие переводы видео (субтитры) по этой теме: Tag: Architecture Components
Мой клон с русскими субтитрами
:
Оригинальное видео:
Аннотация к видео:
- Handling Application & UI lifecycle on Android has always been a challenge for applications: subclassing, overriding, and entirely too much code in your Activity class leads to fragile, complicated application logic. Wouldn’t it be nice if this was easier? This session will cover a new approach to lifecycles and explore functionality that makes the problem dramatically easier. Be sure to also check out the other two “Architecture Components” sessions for more information on architecting better Android applications.
Перевод:
- Управление жизненным циклом приложений и пользовательского интерфейса на Android всегда было проблемой для приложений: подклассы, переопределение и слишком много кода в классе Activity приводят к хрупкой, сложной логике приложений. Было бы неплохо, если бы это было проще? В этой сессии попробуем охватить новый подход к жизненным циклам и изучить функциональность, которая значительно упростит проблему. Обязательно ознакомьтесь с двумя другими разделами «Компоненты архитектуры» для получения дополнительной информации об архитектуре лучших приложений для Android.
Ссылки к видео:
- единая точка входа для архитектурных компонентов - LiveData, ViewModel, LifecycleObserver, LifecycleOwner, Room (абстрация над SQLite базой данных), etc.
- Android Persistence: Room Library - tutorial codelab.
- о Room - article with Kotlin.
- Room, ViewModel, LifeCycle, LiveData - article
- Android lifecycle-aware components - tutorial codelab.
- Architecture Components: Improve Your App’s Design - видео-обзор от Google новых архитектурных компонентов, 5 мин 41 сек на просмотр.
English | Русский |
---|---|
1 00:00:00,000 --> 00:00:06,201 [MUSIC PLAYING] 2 00:00:06,201 --> 00:00:09,380 SERGEI VASILINETC: Good morning, everyone. 3 00:00:09,380 --> 00:00:10,130 My name is Sergei. 4 00:00:10,130 --> 00:00:12,620 This is Adam and Yigit with me today, 5 00:00:12,620 --> 00:00:15,780 and we will speak about LifeCycle problems. 6 00:00:15,780 --> 00:00:21,240 So probably many of you attended yesterday at Yigit's talk 7 00:00:21,240 --> 00:00:24,670 where he introduced new architecture components. 8 00:00:24,670 --> 00:00:27,550 He introduced LiveData, ViewModel, new persistence 9 00:00:27,550 --> 00:00:28,540 slide named Room. 10 00:00:28,540 --> 00:00:31,900 And today we will focus on the LifeCycle part 11 00:00:31,900 --> 00:00:34,990 of these architectural components. 12 00:00:34,990 --> 00:00:37,715 So we will speak again about LiveData And ViewModel. 13 00:00:37,715 --> 00:00:41,140 We will speak about LifeCycle honors and LifeCycle that 14 00:00:41,140 --> 00:00:45,210 are basics for these libraries. 15 00:00:45,210 --> 00:00:49,150 But we will have more details. 16 00:00:49,150 --> 00:00:51,890 We will have some reasoning behind our decisions. 17 00:00:51,890 --> 00:00:56,360 So if you attended yesterday, it will be still interesting. 18 00:00:56,360 --> 00:00:57,900 If you didn't attend yesterday, we 19 00:00:57,900 --> 00:00:59,600 will reintroduce all of these things 20 00:00:59,600 --> 00:01:03,370 so you will understand everything. 21 00:01:03,370 --> 00:01:07,480 So let's see what we have today. 22 00:01:07,480 --> 00:01:11,280 Today we have an activity in the fragments. 23 00:01:11,280 --> 00:01:14,300 I'll start with is that not for length length but dozens 24 00:01:14,300 --> 00:01:17,330 and dozens line of lines. 25 00:01:17,330 --> 00:01:22,190 And this line's the results from a very natural process. 26 00:01:22,190 --> 00:01:24,690 Google pay services asked to register them 27 00:01:24,690 --> 00:01:25,670 in onStart methods. 28 00:01:25,670 --> 00:01:29,620 It's Your own components need to know about this LifeCycle 29 00:01:29,620 --> 00:01:34,640 event, so you need to forward them in some kind of API. 30 00:01:34,640 --> 00:01:38,100 And correspondingly, on onStop method, 31 00:01:38,100 --> 00:01:42,530 you have to call all pairings stop methods, 32 00:01:42,530 --> 00:01:44,900 and it's very easy to forget one. 33 00:01:44,900 --> 00:01:46,880 And will result in [INAUDIBLE]. 34 00:01:46,880 --> 00:01:51,950 It will drain the user's battery, 35 00:01:51,950 --> 00:01:54,920 and they will enjoy your app a bit less. 36 00:01:54,920 --> 00:01:58,190 Which is probably healthier for them, but we think that's bad. 37 00:01:58,190 --> 00:02:02,180 And they think the answer in this situation 38 00:02:02,180 --> 00:02:04,130 is to introduce LifeCycle aware components. 39 00:02:04,130 --> 00:02:06,770 So components which handle LifeCycle. 40 00:02:06,770 --> 00:02:08,538 And the first step in this direction 41 00:02:08,538 --> 00:02:11,750 is to introduce LifeCycle as a first class citizen. 42 00:02:11,750 --> 00:02:13,550 So it's a very simple object which 43 00:02:13,550 --> 00:02:17,370 answers the question, what is the current state right now? 44 00:02:17,370 --> 00:02:19,130 And notifies you about new events. 45 00:02:19,130 --> 00:02:22,340 And then no feature is important but sounds ridiculous right 46 00:02:22,340 --> 00:02:26,060 now, events and states are different things. 47 00:02:26,060 --> 00:02:28,540 So let's see what I mean. 48 00:02:28,540 --> 00:02:31,610 Your case is instantiated in initialized state. 49 00:02:31,610 --> 00:02:37,965 And all creation phases pass very routinely. 50 00:02:37,965 --> 00:02:39,680 OnCreate, create the state. 51 00:02:39,680 --> 00:02:42,460 OnStart, start the state, same thing for resume. 52 00:02:42,460 --> 00:02:45,070 But the road down is a bit more interesting. 53 00:02:45,070 --> 00:02:48,920 So onPause event, leads you from a resume state 54 00:02:48,920 --> 00:02:50,480 back to a starting state. 55 00:02:50,480 --> 00:02:53,490 Not some new pause state, or something like that. 56 00:02:53,490 --> 00:02:57,870 And the reason for this is from a system perspective, 57 00:02:57,870 --> 00:03:01,880 the states after onPause event and onStart event are the same 58 00:03:01,880 --> 00:03:05,790 because the sets of the actions that you are allowed to do 59 00:03:05,790 --> 00:03:07,010 is the same. 60 00:03:07,010 --> 00:03:11,960 And the same is true for onStop and Creative state. 61 00:03:11,960 --> 00:03:14,350 And last event is onDestroy. 62 00:03:14,350 --> 00:03:18,390 It's pretty straightforward. 63 00:03:18,390 --> 00:03:20,150 It brings it to destroy state. 64 00:03:20,150 --> 00:03:21,730 Your activity is destroyed. 65 00:03:21,730 --> 00:03:25,720 It's going to be thrown away and garbage collected. 66 00:03:25,720 --> 00:03:28,020 So let's make our component LifeCycle aware. 67 00:03:28,020 --> 00:03:29,390 That's super straightforward. 68 00:03:29,390 --> 00:03:32,780 We take it with LifeCycle observer interface, 69 00:03:32,780 --> 00:03:34,350 accepted interface. 70 00:03:34,350 --> 00:03:40,320 To get the actual events, we add annotation and pass the events 71 00:03:40,320 --> 00:03:43,200 that we are interested in, you can pass multiple events 72 00:03:43,200 --> 00:03:43,950 if you want to. 73 00:03:43,950 --> 00:03:48,180 The last step is to add ourselves as an observer. 74 00:03:48,180 --> 00:03:53,910 And we may have a potential problem here. 75 00:03:53,910 --> 00:03:57,810 What if the activity is already started at this point? 76 00:03:57,810 --> 00:04:02,730 Does this mean that we are going to receive onStop event, 77 00:04:02,730 --> 00:04:05,970 and and we didn't receive onStart. 78 00:04:05,970 --> 00:04:09,540 And our component probably is not ready for this. 79 00:04:09,540 --> 00:04:12,570 But it took care of it, and we bring 80 00:04:12,570 --> 00:04:14,412 the observer to correct state. 81 00:04:14,412 --> 00:04:15,370 So what does this mean? 82 00:04:15,370 --> 00:04:17,670 Let's take this example, which I just discussed. 83 00:04:17,670 --> 00:04:20,610 From activity perspective onStart and onCreate 84 00:04:20,610 --> 00:04:26,250 create already happened, and after that we add an observer. 85 00:04:26,250 --> 00:04:31,740 But observer will still receive onCreate and onStart events 86 00:04:31,740 --> 00:04:34,950 immediately when they were registered. 87 00:04:34,950 --> 00:04:38,130 So let's take one step further. 88 00:04:38,130 --> 00:04:39,870 OnResume, same situation. 89 00:04:39,870 --> 00:04:41,400 Resume state will bring to resume 90 00:04:41,400 --> 00:04:45,550 state we got an onResume event in addition to onCreate 91 00:04:45,550 --> 00:04:46,610 and onStart. 92 00:04:46,610 --> 00:04:48,660 A bit more interesting situation, 93 00:04:48,660 --> 00:04:54,590 onPause In this situation, we are in a start state as well as 94 00:04:54,590 --> 00:04:55,830 we learned. 95 00:04:55,830 --> 00:04:59,060 So we bring the oberserver to the correct state 96 00:04:59,060 --> 00:05:00,030 which is start. 97 00:05:00,030 --> 00:05:04,040 So it's a similar situation as we had one minute ago. 98 00:05:04,040 --> 00:05:06,930 Observer will receive onCreate and onStart events, 99 00:05:06,930 --> 00:05:09,090 and that's it. 100 00:05:09,090 --> 00:05:13,460 So we don't have a problem in this code. 101 00:05:13,460 --> 00:05:17,240 So how to get this magical lifecycle object? 102 00:05:17,240 --> 00:05:20,940 We have this interface which is super simple, 103 00:05:20,940 --> 00:05:25,060 but this probably doesn't help much right now. 104 00:05:25,060 --> 00:05:26,580 And the actual question is who are 105 00:05:26,580 --> 00:05:29,600 LifeCycle owners out of box. 106 00:05:29,600 --> 00:05:34,310 And the answer in this question is support library fragments 107 00:05:34,310 --> 00:05:35,630 and support activities. 108 00:05:35,630 --> 00:05:40,140 But unfortunately, this is true only in the bright future. 109 00:05:40,140 --> 00:05:44,300 And right now we have LifeCycle activity 110 00:05:44,300 --> 00:05:46,040 and LifeCycle fragment. 111 00:05:46,040 --> 00:05:49,520 But at the point of 1.0 release, we 112 00:05:49,520 --> 00:05:53,720 will merge our library to support libraries so you 113 00:05:53,720 --> 00:05:56,070 don't have to use them later. 114 00:05:56,070 --> 00:05:59,400 And now Adam will speak about some key differences 115 00:05:59,400 --> 00:06:02,242 between fragment and LifeCyle observers 116 00:06:02,242 --> 00:06:04,200 ADAM POWELL: So if you've been following along, 117 00:06:04,200 --> 00:06:06,616 you probably recognize some similarities with the fragment 118 00:06:06,616 --> 00:06:07,950 API in this as well. 119 00:06:07,950 --> 00:06:10,850 So at this point we've got these two different components. 120 00:06:10,850 --> 00:06:12,480 Which one do you use? 121 00:06:12,480 --> 00:06:14,870 Well, as the slides are already spoiling for you, 122 00:06:14,870 --> 00:06:17,594 this really isn't an either- or question. 123 00:06:17,594 --> 00:06:20,010 One of these things doesn't necessarily replace the other. 124 00:06:20,010 --> 00:06:22,040 And here's why. 125 00:06:22,040 --> 00:06:25,830 Fragments, on one hand, that everybody knows and loves, 126 00:06:25,830 --> 00:06:28,190 are statefully managed and recreated 127 00:06:28,190 --> 00:06:32,030 after either a process death, an activity recreation, 128 00:06:32,030 --> 00:06:35,630 or recreation of any hosts that you have the fragment within. 129 00:06:35,630 --> 00:06:37,760 Fragments manage views and also interact 130 00:06:37,760 --> 00:06:39,620 with the navigation stack, which are 131 00:06:39,620 --> 00:06:42,230 things that are firmly out of scope of what LifeCycle 132 00:06:42,230 --> 00:06:43,880 observers are meant to do. 133 00:06:43,880 --> 00:06:45,740 Instead, LifeCycle observers are meant 134 00:06:45,740 --> 00:06:47,930 to enable more granular factoring of your code, 135 00:06:47,930 --> 00:06:50,360 whether you're in an activity or a fragment. 136 00:06:50,360 --> 00:06:51,110 They're stateless. 137 00:06:51,110 --> 00:06:53,570 So that means that they must be registered each time 138 00:06:53,570 --> 00:06:54,770 the owner is recreated. 139 00:06:54,770 --> 00:06:56,186 We're not going to try to recreate 140 00:06:56,186 --> 00:06:57,290 these magically for you. 141 00:06:57,290 --> 00:06:59,150 They don't have any concept of instant state 142 00:06:59,150 --> 00:07:00,780 that they carry around with them. 143 00:07:00,780 --> 00:07:02,510 So these are meant to be very, very lightweight, 144 00:07:02,510 --> 00:07:04,968 so that you don't have a whole lot of additional management 145 00:07:04,968 --> 00:07:06,170 overhead. 146 00:07:06,170 --> 00:07:09,470 And last, there's no relation to the viewer navigation 147 00:07:09,470 --> 00:07:10,010 management. 148 00:07:10,010 --> 00:07:12,470 These really are meant to be very tightly 149 00:07:12,470 --> 00:07:16,330 scoped, isolated components. 150 00:07:16,330 --> 00:07:17,950 So they can really help everyone. 151 00:07:17,950 --> 00:07:21,040 It means that it's much simpler to integrate libraries 152 00:07:21,040 --> 00:07:23,860 with your code, as long as those libraries have provided 153 00:07:23,860 --> 00:07:26,124 LifeCycle observer aware components. 154 00:07:26,124 --> 00:07:28,540 It means that you can break up those really large fragment 155 00:07:28,540 --> 00:07:31,300 or activity classes to make them much simpler to understand 156 00:07:31,300 --> 00:07:32,440 for a reader. 157 00:07:32,440 --> 00:07:35,200 And you can provide much more granular guarantees 158 00:07:35,200 --> 00:07:38,660 around what operations are valid at any given point in time. 159 00:07:38,660 --> 00:07:41,860 You can make it so that if an operation happens then 160 00:07:41,860 --> 00:07:44,050 you're guaranteed to be in a correct state 161 00:07:44,050 --> 00:07:45,130 when something is called. 162 00:07:45,130 --> 00:07:48,060 163 00:07:48,060 --> 00:07:50,685 So LifeCycle owner as already introduced 164 00:07:50,685 --> 00:07:51,900 is just an interface. 165 00:07:51,900 --> 00:07:53,630 Anyone can implement this. 166 00:07:53,630 --> 00:07:55,680 This means that you can improve testability 167 00:07:55,680 --> 00:07:56,802 by creating your own. 168 00:07:56,802 --> 00:07:59,010 You can create your own sort of fragment-like library 169 00:07:59,010 --> 00:08:01,170 implementations if you feel so inclined. 170 00:08:01,170 --> 00:08:03,330 But you can also create composite life cycles. 171 00:08:03,330 --> 00:08:06,780 Life cycles that span across other smaller lifecycle 172 00:08:06,780 --> 00:08:08,010 definitions. 173 00:08:08,010 --> 00:08:10,710 So you can answer questions like, is my app visible? 174 00:08:10,710 --> 00:08:12,750 So this is a really common composite lifecycle 175 00:08:12,750 --> 00:08:15,000 that many of you may be interested in. 176 00:08:15,000 --> 00:08:17,160 It lets you do things like session management 177 00:08:17,160 --> 00:08:19,530 to track a particular session across perhaps 178 00:08:19,530 --> 00:08:23,100 some sort of a flow or a series of logged 179 00:08:23,100 --> 00:08:24,870 in versus logged out events. 180 00:08:24,870 --> 00:08:29,020 And it may help you with analytics as well. 181 00:08:29,020 --> 00:08:32,280 So we have the process LifeCycle owner as kind of a component 182 00:08:32,280 --> 00:08:35,350 that I think a lot of you will be interested in for this. 183 00:08:35,350 --> 00:08:39,058 It's the composite lifecycle of all the activities in your app. 184 00:08:39,058 --> 00:08:41,009 So there's no configuration changes to handle, 185 00:08:41,010 --> 00:08:44,440 because we're not going to be dealing with those from these. 186 00:08:44,440 --> 00:08:46,350 The process LifeCycle owner just stays 187 00:08:46,350 --> 00:08:48,000 alive through the whole process. 188 00:08:48,000 --> 00:08:50,041 But that also means that you don't get state risk 189 00:08:50,041 --> 00:08:52,660 restoration after process death like we mentioned earlier. 190 00:08:52,660 --> 00:08:54,600 So that means that you don't have 191 00:08:54,600 --> 00:08:56,905 to handle saving and restoring that state 192 00:08:56,905 --> 00:08:59,280 but at the same time, you need to remember to re-register 193 00:08:59,280 --> 00:09:02,199 these process lifecycle-based observers if that's something 194 00:09:02,199 --> 00:09:03,240 that you're working with. 195 00:09:03,240 --> 00:09:05,750 196 00:09:05,750 --> 00:09:09,110 So many indirect components provide a lot 197 00:09:09,110 --> 00:09:11,330 of deep plumbing layers for things 198 00:09:11,330 --> 00:09:13,790 that you can plug into and work with. 199 00:09:13,790 --> 00:09:15,800 But a lot of times we've kind of omitted 200 00:09:15,800 --> 00:09:17,720 the idea of higher level components that 201 00:09:17,720 --> 00:09:20,210 make use of that plumbing so that you can just plug 202 00:09:20,210 --> 00:09:21,280 play and go. 203 00:09:21,280 --> 00:09:24,300 So do we have anything more high level than the bare events 204 00:09:24,300 --> 00:09:25,530 and states here? 205 00:09:25,530 --> 00:09:26,800 YIGIT BOYAR: Maybe we do. 206 00:09:26,800 --> 00:09:27,760 I will show you. 207 00:09:27,760 --> 00:09:28,870 ADAM POWELL: Great 208 00:09:28,870 --> 00:09:30,530 YIGIT BOYAR: Thanks, Adam. 209 00:09:30,530 --> 00:09:33,680 So it's so nice now you can observe 210 00:09:33,680 --> 00:09:37,310 a LifeCycle is well-defined, is a first class citizen. 211 00:09:37,310 --> 00:09:40,530 But you still need to deal with these things. 212 00:09:40,530 --> 00:09:44,780 And we told like, there's some common LifeCycle problems 213 00:09:44,780 --> 00:09:47,100 that we should be able to solve with this component. 214 00:09:47,100 --> 00:09:48,860 So we'll look at the problems that people 215 00:09:48,860 --> 00:09:51,740 are having, and this was probably 216 00:09:51,740 --> 00:09:54,110 the most major problem we've been seeing, 217 00:09:54,110 --> 00:09:56,320 the untimely UI updates. 218 00:09:56,320 --> 00:09:58,920 It's like your activity receives a callback, 219 00:09:58,920 --> 00:10:00,530 but the activity's already stopped. 220 00:10:00,530 --> 00:10:03,050 They tried to start a new activity and crashes. 221 00:10:03,050 --> 00:10:06,010 Or it tries to add a fragment and crashes. 222 00:10:06,010 --> 00:10:09,410 If an activity or a fragment is stopped, 223 00:10:09,410 --> 00:10:12,317 there is no reason to update that activity. 224 00:10:12,317 --> 00:10:13,400 You don't want to do that. 225 00:10:13,400 --> 00:10:16,190 If the activity happens to become visible again, then 226 00:10:16,190 --> 00:10:17,480 you want to do it. 227 00:10:17,480 --> 00:10:20,480 So we realized that this is a very common problem, 228 00:10:20,480 --> 00:10:23,990 and we wanted to solve this with a higher level component which 229 00:10:23,990 --> 00:10:26,060 we call LiveData. 230 00:10:26,060 --> 00:10:29,780 When we look at the LiveData in detail, 231 00:10:29,780 --> 00:10:32,840 it's actually an observable data holder. 232 00:10:32,840 --> 00:10:35,180 It just holds on to some information 233 00:10:35,180 --> 00:10:36,490 that you can observe. 234 00:10:36,490 --> 00:10:38,270 Now the difference between LiveData 235 00:10:38,270 --> 00:10:41,225 and your other observables in data mining or RxJava 236 00:10:41,225 --> 00:10:45,350 or whatever, is that LiveData is LifeCycle aware. 237 00:10:45,350 --> 00:10:48,020 It knows about Android life cycles, 238 00:10:48,020 --> 00:10:50,030 and when you want to observe a LiveData, 239 00:10:50,030 --> 00:10:52,580 you can pass in this LifeCycle so that it 240 00:10:52,580 --> 00:10:54,480 can manage your subscription. 241 00:10:54,480 --> 00:10:57,210 The nice thing about LiveData that is that you observe, 242 00:10:57,210 --> 00:10:59,340 and that's all you do. 243 00:10:59,340 --> 00:11:00,860 So if we look at the usage example, 244 00:11:00,860 --> 00:11:02,210 let's say we have an activity. 245 00:11:02,210 --> 00:11:04,110 We receive a LiveData from somewhere. 246 00:11:04,110 --> 00:11:08,040 It doesn't really matter, and now we call observe on it. 247 00:11:08,040 --> 00:11:10,160 And when we are calling observe, we 248 00:11:10,160 --> 00:11:13,600 are passing this, which is the LiveData owner. 249 00:11:13,600 --> 00:11:14,780 That's all you need to say. 250 00:11:14,780 --> 00:11:18,770 I want to observe this LiveData within this LifeCycle. 251 00:11:18,770 --> 00:11:21,830 Which also means if this LifeCycle is gone, 252 00:11:21,830 --> 00:11:23,150 I don't want to observe it. 253 00:11:23,150 --> 00:11:26,550 Or if this LifeCycle is stopped, I don't want to receive events. 254 00:11:26,550 --> 00:11:30,466 255 00:11:30,466 --> 00:11:32,340 And then once you do this, that's all you do. 256 00:11:32,340 --> 00:11:34,410 You don't need to write onStart, onStop. 257 00:11:34,410 --> 00:11:37,870 We want Android to want to look more like this. 258 00:11:37,870 --> 00:11:40,040 You initialze things as more like find and forget. 259 00:11:40,040 --> 00:11:43,060 You initialize, and you're done. 260 00:11:43,060 --> 00:11:45,990 So let's look at what happens when our activity starts 261 00:11:45,990 --> 00:11:47,910 observing that LiveData. 262 00:11:47,910 --> 00:11:52,560 So onCreate, it called observe, it said LiveData is observable. 263 00:11:52,560 --> 00:11:54,630 And as soon as the activity starts, 264 00:11:54,630 --> 00:11:56,470 it starts receiving data changes. 265 00:11:56,470 --> 00:11:59,490 So whenever the LiveData value changes, 266 00:11:59,490 --> 00:12:01,950 we displace that event back to your observer 267 00:12:01,950 --> 00:12:03,530 inside the activity. 268 00:12:03,530 --> 00:12:05,450 It can also be a fragment. 269 00:12:05,450 --> 00:12:07,260 Let's say a user decides to rotate 270 00:12:07,260 --> 00:12:09,090 the activity at this moment. 271 00:12:09,090 --> 00:12:11,540 So you know that the activity will be stopped. 272 00:12:11,540 --> 00:12:13,320 And what happens at the same time, 273 00:12:13,320 --> 00:12:16,110 the LiveData happens to be updated. 274 00:12:16,110 --> 00:12:18,990 If that happens, we are not going to tell the activity 275 00:12:18,990 --> 00:12:22,590 about this change because there cannot be any reason for you 276 00:12:22,590 --> 00:12:27,210 to update the UI, because it already stopped. 277 00:12:27,210 --> 00:12:29,640 Similarly, if the activity is destroyed, 278 00:12:29,640 --> 00:12:31,980 we will automatically remove that subscription 279 00:12:31,980 --> 00:12:34,320 because that activity is gone. 280 00:12:34,320 --> 00:12:36,990 There is no reason to keep a reference back 281 00:12:36,990 --> 00:12:39,240 to that activity. 282 00:12:39,240 --> 00:12:41,010 Now we said the activity was rotating, 283 00:12:41,010 --> 00:12:42,630 so you know that Android is going 284 00:12:42,630 --> 00:12:44,880 to recreate that activity. 285 00:12:44,880 --> 00:12:48,270 And then we are observing the same LiveData back. 286 00:12:48,270 --> 00:12:49,985 As soon as that activity starts, it's 287 00:12:49,985 --> 00:12:53,190 going to receive last available data. 288 00:12:53,190 --> 00:12:57,720 So your UI is going to have the data before it gets a chance 289 00:12:57,720 --> 00:12:59,790 to draw. 290 00:12:59,790 --> 00:13:01,920 So similarly, I say the user hits 291 00:13:01,920 --> 00:13:05,330 the Home button, which means the activity will be stopped. 292 00:13:05,330 --> 00:13:08,700 Again, if the LiveData changes while the activity is stopped, 293 00:13:08,700 --> 00:13:10,840 it's not going to receive any events. 294 00:13:10,840 --> 00:13:14,010 Even if the data changes, we are not going to tell it. 295 00:13:14,010 --> 00:13:17,280 But as soon as if the user comes back to the application, 296 00:13:17,280 --> 00:13:19,510 we will give it the last available data. 297 00:13:19,510 --> 00:13:22,990 So this is why we call LiveData is not just a stream of events. 298 00:13:22,990 --> 00:13:26,910 It holds onto the data so that if any observer comes, 299 00:13:26,910 --> 00:13:30,430 it receives the last available value. 300 00:13:30,430 --> 00:13:33,620 And then eventually, the user backs out of that activity, 301 00:13:33,620 --> 00:13:37,830 and then we remove that subscription. 302 00:13:37,830 --> 00:13:40,730 You can also extend the LiveData class. 303 00:13:40,730 --> 00:13:45,950 Because LiveData provides two really handy callbacks. 304 00:13:45,950 --> 00:13:48,410 The first one is called onactive which means 305 00:13:48,410 --> 00:13:50,930 you have an active observer. 306 00:13:50,930 --> 00:13:52,580 Another one is called oninactive, 307 00:13:52,580 --> 00:13:54,370 which means you don't have any observers, 308 00:13:54,370 --> 00:13:56,450 so don't bother changing your value 309 00:13:56,450 --> 00:14:00,020 if it is something that you care about. 310 00:14:00,020 --> 00:14:03,800 You probably ask now what is an active observer? 311 00:14:03,800 --> 00:14:06,220 An active observer is an observer 312 00:14:06,220 --> 00:14:09,680 whose attached LifeCycle is started or resumed. 313 00:14:09,680 --> 00:14:12,890 So it's like a fragment that's currently visible to the user. 314 00:14:12,890 --> 00:14:15,380 If the fragment is on the back stack, 315 00:14:15,380 --> 00:14:16,660 the user is not seeing it. 316 00:14:16,660 --> 00:14:18,260 It stopped, so it's not active. 317 00:14:18,260 --> 00:14:22,430 There's no reason to do any work for that fragment. 318 00:14:22,430 --> 00:14:24,850 Let's see how we can take advantage of these named 319 00:14:24,850 --> 00:14:25,770 callbacks. 320 00:14:25,770 --> 00:14:28,270 We are going to create a new location LiveData 321 00:14:28,270 --> 00:14:31,190 class, which presents the location of something 322 00:14:31,190 --> 00:14:32,580 on the device. 323 00:14:32,580 --> 00:14:37,920 So we say this data holds an instance of a location. 324 00:14:37,920 --> 00:14:40,460 In cross-sector, we just get the location manager 325 00:14:40,460 --> 00:14:41,850 from the system service. 326 00:14:41,850 --> 00:14:43,670 There's nothing fancy here. 327 00:14:43,670 --> 00:14:47,210 We have a listener whenever the system server sends us 328 00:14:47,210 --> 00:14:50,830 any location, we just call setValue on us. 329 00:14:50,830 --> 00:14:51,530 This all you do. 330 00:14:51,530 --> 00:14:53,460 There is no LifeCycle handling here. 331 00:14:53,460 --> 00:14:56,120 You just call setValue, and LiveData takes 332 00:14:56,120 --> 00:14:57,710 care of handling the LifeCycle. 333 00:14:57,710 --> 00:15:00,080 And you may have any number of observers. 334 00:15:00,080 --> 00:15:02,450 It doesn't really matter. 335 00:15:02,450 --> 00:15:04,850 So we want to override onactive. 336 00:15:04,850 --> 00:15:07,340 The very first active observer comes. 337 00:15:07,340 --> 00:15:10,280 We want to start listening to the system service. 338 00:15:10,280 --> 00:15:14,300 Similarly, when the last active observer goes away, 339 00:15:14,300 --> 00:15:19,140 we want to stop observing the system service. 340 00:15:19,140 --> 00:15:21,800 Now if you look at that location LiveData class 341 00:15:21,800 --> 00:15:24,020 we just created in the previous example, let's look 342 00:15:24,020 --> 00:15:26,210 at the properties of that class. 343 00:15:26,210 --> 00:15:28,100 First of all, it is LifeCycle area. 344 00:15:28,100 --> 00:15:31,280 It knows when to start itself, when to stop itself. 345 00:15:31,280 --> 00:15:34,340 You just don't need to babysit it anymore. 346 00:15:34,340 --> 00:15:36,110 It is self-sufficient. 347 00:15:36,110 --> 00:15:37,140 You start it. 348 00:15:37,140 --> 00:15:39,480 You forget about it. 349 00:15:39,480 --> 00:15:40,470 It can be a singleton. 350 00:15:40,470 --> 00:15:42,620 Like all of the subscriptions are automatically 351 00:15:42,620 --> 00:15:43,850 managed for you. 352 00:15:43,850 --> 00:15:47,090 So if the data is logically singleton your codebase, 353 00:15:47,090 --> 00:15:50,030 you can make the LiveData instance singleton. 354 00:15:50,030 --> 00:15:51,710 So there's this thing where normally 355 00:15:51,710 --> 00:15:54,800 if you keep referencing an activity or a fragment 356 00:15:54,800 --> 00:15:57,720 from a certain context, that will be a big no no. 357 00:15:57,720 --> 00:16:00,350 But if you are using LiveData it is yes yes, 358 00:16:00,350 --> 00:16:05,340 because we manage the substitution for you. 359 00:16:05,340 --> 00:16:08,550 So you also don't need to subclass LiveData all the time. 360 00:16:08,550 --> 00:16:10,910 So if you just need an instance of it 361 00:16:10,910 --> 00:16:12,790 but you already have the value, you 362 00:16:12,790 --> 00:16:14,990 could use this mutable LiveData class, 363 00:16:14,990 --> 00:16:18,770 which comes inside the library that has a public setter. 364 00:16:18,770 --> 00:16:21,170 But usually when you are using this class, 365 00:16:21,170 --> 00:16:24,530 internally you will have it but the API you expose 366 00:16:24,530 --> 00:16:26,360 will just return a LiveData, because you 367 00:16:26,360 --> 00:16:28,370 don't want to expose the fact that anyone 368 00:16:28,370 --> 00:16:31,470 can set the value on it. 369 00:16:31,470 --> 00:16:34,920 Now when we were designing these LifeCycle components, 370 00:16:34,920 --> 00:16:38,730 the LiveData, see we spent a lot of time 371 00:16:38,730 --> 00:16:41,380 to get rid of one exception. 372 00:16:41,380 --> 00:16:43,350 This fragment exception that I-- 373 00:16:43,350 --> 00:16:50,520 [APPLAUSE] 374 00:16:50,520 --> 00:16:54,350 We really wanted to say, please, no more fragment transaction 375 00:16:54,350 --> 00:16:55,460 exceptions. 376 00:16:55,460 --> 00:16:58,570 So LiveData guarantees that if you received anywhere, 377 00:16:58,570 --> 00:17:00,910 you could run a fragment transaction. 378 00:17:00,910 --> 00:17:05,310 And to see how we are making it part of the history, 379 00:17:05,310 --> 00:17:10,118 I want to invite Adam back to explain it to us. 380 00:17:10,118 --> 00:17:11,539 ADAM POWELL: All right, so anyone 381 00:17:11,540 --> 00:17:13,205 who has received one of these exceptions 382 00:17:13,205 --> 00:17:15,289 realizes that it doesn't just come 383 00:17:15,290 --> 00:17:18,710 from trying to do something when you just completely stopped 384 00:17:18,710 --> 00:17:20,348 and you absolutely know it. 385 00:17:20,348 --> 00:17:21,889 These exceptions tend to come in when 386 00:17:21,890 --> 00:17:26,010 you get into very intricate, nested life cycles. 387 00:17:26,010 --> 00:17:28,910 So we wanted to make sure to be very thoughtful about defining 388 00:17:28,910 --> 00:17:34,190 how the LifeCycle observer callbacks are invoked and when. 389 00:17:34,190 --> 00:17:37,400 So in a case like this, what happens? 390 00:17:37,400 --> 00:17:42,120 You have defined handler for the stop event. 391 00:17:42,120 --> 00:17:44,872 So in the container your activity onStop, 392 00:17:44,872 --> 00:17:47,330 you want to make sure that you don't get an onChanged event 393 00:17:47,330 --> 00:17:48,770 after the onStop has happened. 394 00:17:48,770 --> 00:17:52,660 395 00:17:52,660 --> 00:17:54,570 But in order for that to happen, what 396 00:17:54,570 --> 00:17:56,490 needs to be true about when we actually 397 00:17:56,490 --> 00:18:00,030 invoke all of the onStop listeners 398 00:18:00,030 --> 00:18:02,610 that are attached to these observers. 399 00:18:02,610 --> 00:18:05,770 So we have to define a really strict order for this. 400 00:18:05,770 --> 00:18:09,420 So as we go through create and start and onResume, 401 00:18:09,420 --> 00:18:11,940 we know that we need to invoke the LifeCycle 402 00:18:11,940 --> 00:18:15,480 observers after the container event happens. 403 00:18:15,480 --> 00:18:18,090 So you know in your observer that everything 404 00:18:18,090 --> 00:18:20,461 about your LifeCycle owner has been configured. 405 00:18:20,461 --> 00:18:21,960 If you check any state about it, you 406 00:18:21,960 --> 00:18:25,397 know that you're already completely in that state. 407 00:18:25,397 --> 00:18:27,480 But that means something really special for coming 408 00:18:27,480 --> 00:18:29,470 back down the other direction. 409 00:18:29,470 --> 00:18:33,540 It means that when the activity starts to become paused, 410 00:18:33,540 --> 00:18:34,995 you want your LifeCycle observers 411 00:18:34,995 --> 00:18:36,870 to be able to shut down anything that they're 412 00:18:36,870 --> 00:18:39,060 doing before the activity does all of the work 413 00:18:39,060 --> 00:18:41,400 to actually become paused. 414 00:18:41,400 --> 00:18:42,810 Similar for stop. 415 00:18:42,810 --> 00:18:44,850 And this is where this becomes really 416 00:18:44,850 --> 00:18:47,220 important for the fragment transaction exception. 417 00:18:47,220 --> 00:18:49,260 You want to make sure that you're 418 00:18:49,260 --> 00:18:52,440 recording, that you're fully stopped before the fragment 419 00:18:52,440 --> 00:18:54,600 system goes through and flags everything 420 00:18:54,600 --> 00:18:58,180 as being completely locked out. 421 00:18:58,180 --> 00:19:01,410 So what that means is that the stop event of your LifeCycle 422 00:19:01,410 --> 00:19:04,770 observer will always be invoked before the activity onStop 423 00:19:04,770 --> 00:19:10,710 or before the full stop event for your container happens. 424 00:19:10,710 --> 00:19:13,260 So this seems really similar to some other libraries 425 00:19:13,260 --> 00:19:15,480 that some people may have seen in the past. 426 00:19:15,480 --> 00:19:16,600 Can you talk about that? 427 00:19:16,600 --> 00:19:22,530 SERGEI VASILINETC: Yes, when we create new observable pattern, 428 00:19:22,530 --> 00:19:26,220 nowadays this question is unavoidable. 429 00:19:26,220 --> 00:19:29,220 Is it another RxJava? 430 00:19:29,220 --> 00:19:32,490 And the answer to this question is, yes, 431 00:19:32,490 --> 00:19:34,740 because we want to promote a reactive programming 432 00:19:34,740 --> 00:19:37,980 model, especially when it comes to the relationship 433 00:19:37,980 --> 00:19:40,710 between your UI and the state [INAUDIBLE] UI. 434 00:19:40,710 --> 00:19:45,490 We want you to react on the changes of the state. 435 00:19:45,490 --> 00:19:48,300 So it means that it's a reactive programming model. 436 00:19:48,300 --> 00:19:51,000 But on the other hand, no. 437 00:19:51,000 --> 00:19:54,840 Because it's the LifeCycle aware out of box, 438 00:19:54,840 --> 00:19:57,930 as Yigit mentioned, and it's much easier. 439 00:19:57,930 --> 00:20:02,940 As many of you may know, the learning curve of RxJava 440 00:20:02,940 --> 00:20:04,560 is super steep. 441 00:20:04,560 --> 00:20:08,850 And if you have an Android learner curve, 442 00:20:08,850 --> 00:20:13,350 and after that we add RxJava learning curve on top of it, 443 00:20:13,350 --> 00:20:16,050 it becomes very hard to new people 444 00:20:16,050 --> 00:20:19,420 to start to develop on our platform. 445 00:20:19,420 --> 00:20:25,890 So we can't just say to them, oh let's go, just learn this, 446 00:20:25,890 --> 00:20:27,330 that's it. . 447 00:20:27,330 --> 00:20:32,310 No, but if you already learned RxJava, 448 00:20:32,310 --> 00:20:37,020 we don't expect you to migrate from it to our solution. 449 00:20:37,020 --> 00:20:41,280 Because you already passed the learning curve, 450 00:20:41,280 --> 00:20:45,960 you and your coworkers are comfortable with it, fine. 451 00:20:45,960 --> 00:20:48,190 We are totally fine with this. 452 00:20:48,190 --> 00:20:51,330 But one thing we ask you to do is to be sure 453 00:20:51,330 --> 00:20:53,920 that you manage LifeCycle. 454 00:20:53,920 --> 00:20:58,210 RxJava has common approaches to solve this. 455 00:20:58,210 --> 00:21:02,430 Be sure to use it and everything will be fine. 456 00:21:02,430 --> 00:21:09,885 But when you start a new app, I think this model is the best. 457 00:21:09,885 --> 00:21:15,010 The best is to start the project with LiveData, because it's 458 00:21:15,010 --> 00:21:17,310 simpler, it's faster, it's lightweight, 459 00:21:17,310 --> 00:21:20,270 it's well integrated with a framework. 460 00:21:20,270 --> 00:21:24,970 And if you feel like you love reacting programming a lot, 461 00:21:24,970 --> 00:21:28,480 you want to bring it not only to relation 462 00:21:28,480 --> 00:21:31,930 between UI and the state. 463 00:21:31,930 --> 00:21:33,430 You want to bring it to the business 464 00:21:33,430 --> 00:21:36,340 part of your application. 465 00:21:36,340 --> 00:21:41,070 Then you may consider the addition of RxJava, 466 00:21:41,070 --> 00:21:44,230 because it gives you more power. 467 00:21:44,230 --> 00:21:47,140 And we will actually help you to do that. 468 00:21:47,140 --> 00:21:51,790 We have this extension to our library, which 469 00:21:51,790 --> 00:21:55,780 gives a possibility to create LiveData from Publisher 470 00:21:55,780 --> 00:21:58,930 and create Publisher from LiveData. 471 00:21:58,930 --> 00:22:03,970 So this integration should be quite smooth. 472 00:22:03,970 --> 00:22:07,330 But I want to highlight a key difference between RxJava 473 00:22:07,330 --> 00:22:08,080 and LiveData. 474 00:22:08,080 --> 00:22:11,980 So as Yigit already said, LiveData 475 00:22:11,980 --> 00:22:13,870 is a holder and not a stream. 476 00:22:13,870 --> 00:22:17,320 So we have a reference to the last value, 477 00:22:17,320 --> 00:22:20,290 and observers immediately receive the last value when 478 00:22:20,290 --> 00:22:24,820 they start to observe LiveData. 479 00:22:24,820 --> 00:22:27,550 And now the big difference is a threading model. 480 00:22:27,550 --> 00:22:31,840 As you know, RxJava has a very sophisticated threading model. 481 00:22:31,840 --> 00:22:35,390 It's extremely powerful, but in most cases, 482 00:22:35,390 --> 00:22:37,610 you probably don't need it. 483 00:22:37,610 --> 00:22:40,360 And we have everything on the main thread. 484 00:22:40,360 --> 00:22:42,190 And the reason for this is we want 485 00:22:42,190 --> 00:22:47,150 to give you all these guarantees about when we will notify you 486 00:22:47,150 --> 00:22:50,740 about state changes. 487 00:22:50,740 --> 00:22:56,200 And we can't do this on a background thread. 488 00:22:56,200 --> 00:22:58,330 We have just the one exception. 489 00:22:58,330 --> 00:23:00,850 We have a post value method which 490 00:23:00,850 --> 00:23:03,720 just is a method which trampoline value 491 00:23:03,720 --> 00:23:07,725 from a background thread to the main thread and sets it there. 492 00:23:07,725 --> 00:23:08,770 It's super simple. 493 00:23:08,770 --> 00:23:11,400 So quick summary of what we have at this point. 494 00:23:11,400 --> 00:23:13,870 LiveData events, observable pattern 495 00:23:13,870 --> 00:23:16,460 which respects these events. 496 00:23:16,460 --> 00:23:20,090 But there is one big thing which is not covered yet. 497 00:23:20,090 --> 00:23:23,590 And this is how to handle onConfigurationChanges. 498 00:23:23,590 --> 00:23:28,690 In 2017, almost nine years after Android 499 00:23:28,690 --> 00:23:32,050 was first time released, we still discuss this question. 500 00:23:32,050 --> 00:23:34,090 And this is a totally legit question. 501 00:23:34,090 --> 00:23:38,290 And we hear it constantly from new Android developers. 502 00:23:38,290 --> 00:23:40,730 Many of you probably know whats the deal with it. 503 00:23:40,730 --> 00:23:44,770 But let's take a look at this oversimplified example, 504 00:23:44,770 --> 00:23:47,830 but it's still very vivid. 505 00:23:47,830 --> 00:23:50,050 So he wants to show this information 506 00:23:50,050 --> 00:23:52,060 about user and your activity. 507 00:23:52,060 --> 00:23:54,830 And you want to make some web service request. 508 00:23:54,830 --> 00:24:00,340 We will use LiveData to get this result. It's super simple. 509 00:24:00,340 --> 00:24:02,800 When the request is just started, it's empty. 510 00:24:02,800 --> 00:24:06,620 When the request response is received, 511 00:24:06,620 --> 00:24:11,740 we put it to LiveData as a value. 512 00:24:11,740 --> 00:24:14,070 And later we'll update our UI. 513 00:24:14,070 --> 00:24:19,917 We will notify the activity, and it will do everything it needs. 514 00:24:19,917 --> 00:24:22,250 So what happens if the activity is going to [INAUDIBLE]. 515 00:24:22,250 --> 00:24:25,750 We're going to make a call twice, 516 00:24:25,750 --> 00:24:28,560 and I hope that you don't call web service right 517 00:24:28,560 --> 00:24:29,740 into your activity. 518 00:24:29,740 --> 00:24:33,670 But you probably have some abstractions 519 00:24:33,670 --> 00:24:36,010 that does something like that, which 520 00:24:36,010 --> 00:24:41,040 goes to a network, which goes to caching and persistence 521 00:24:41,040 --> 00:24:43,030 storages. 522 00:24:43,030 --> 00:24:47,170 And all the separations are synchronized by nature. 523 00:24:47,170 --> 00:24:51,070 So communication of these components are synchronized. 524 00:24:51,070 --> 00:24:55,510 And you probably don't want to make these calls twice anyway. 525 00:24:55,510 --> 00:24:58,060 So what you want to do is to cache. 526 00:24:58,060 --> 00:25:01,470 This is our data, like in our example. 527 00:25:01,470 --> 00:25:04,480 And what are the ways today to do that? 528 00:25:04,480 --> 00:25:06,960 Well, one of a proposed way to do it 529 00:25:06,960 --> 00:25:10,570 is a Fragment.setRetainInstance, and Yigit 530 00:25:10,570 --> 00:25:12,340 can rant about this for hours. 531 00:25:12,340 --> 00:25:14,770 Unfortunately, we don't have time for this today. 532 00:25:14,770 --> 00:25:17,600 But I just say that the only effect 533 00:25:17,600 --> 00:25:19,900 that you have to run fragment transaction 534 00:25:19,900 --> 00:25:22,400 is terrifying for a lot of people. 535 00:25:22,400 --> 00:25:25,780 People go nuts and another possible way 536 00:25:25,780 --> 00:25:29,960 to solve this is loaders, but we don't fit here well as well. 537 00:25:29,960 --> 00:25:33,010 So we decided to tackle this problem once again 538 00:25:33,010 --> 00:25:35,230 and create ViewModel. 539 00:25:35,230 --> 00:25:36,030 So what is this? 540 00:25:36,030 --> 00:25:39,070 ViewModel is an object which is associated 541 00:25:39,070 --> 00:25:41,440 with a fragment or an activity, but is retained 542 00:25:41,440 --> 00:25:43,750 during configuration changes. 543 00:25:43,750 --> 00:25:48,190 So its scope is a kind of a logical scope of your activity. 544 00:25:48,190 --> 00:25:51,300 So what does this mean? 545 00:25:51,300 --> 00:25:51,900 Let's see. 546 00:25:51,900 --> 00:25:54,220 If we have access time and the current moment, and we 547 00:25:54,220 --> 00:25:55,540 can predict the future. 548 00:25:55,540 --> 00:25:57,670 And we know that activity is going to be created, 549 00:25:57,670 --> 00:25:59,390 and this means that all construction 550 00:25:59,390 --> 00:26:01,690 events are going to happen. 551 00:26:01,690 --> 00:26:05,440 During onCreate we will request ViewModel for the first time. 552 00:26:05,440 --> 00:26:07,780 We will create it, and after that this activity 553 00:26:07,780 --> 00:26:10,850 just uses this ViewModel. 554 00:26:10,850 --> 00:26:12,220 Very simple. 555 00:26:12,220 --> 00:26:16,060 Now we predict that the activity is going to be rotated. 556 00:26:16,060 --> 00:26:20,700 Let's see what's going to happen with our ViewModel. 557 00:26:20,700 --> 00:26:27,400 We will receive events, onPause, onStop, and onDestroy. 558 00:26:27,400 --> 00:26:30,880 But when all the segments are cured 559 00:26:30,880 --> 00:26:34,090 and your activity is destroyed, it's thrown away 560 00:26:34,090 --> 00:26:38,210 and is garbage collected, ViewModel survived it. 561 00:26:38,210 --> 00:26:42,070 And the new activity, which was created in place the old one 562 00:26:42,070 --> 00:26:44,510 uses the same, old object. 563 00:26:44,510 --> 00:26:48,520 So you can easily cache there LiveData as we want to 564 00:26:48,520 --> 00:26:50,690 or something else. 565 00:26:50,690 --> 00:26:52,720 The last case, what is going to happen 566 00:26:52,720 --> 00:26:55,600 if you have finished goal? 567 00:26:55,600 --> 00:26:58,280 Once again, we will receive these destruction events, 568 00:26:58,280 --> 00:27:01,570 but this time, ViewModel is available 569 00:27:01,570 --> 00:27:03,130 until onDestroy method. 570 00:27:03,130 --> 00:27:08,340 During onDestroy method, we will call onClear on this. 571 00:27:08,340 --> 00:27:11,860 Which notifies you if you have any currently running actions 572 00:27:11,860 --> 00:27:15,610 or any resources its time to close. 573 00:27:15,610 --> 00:27:18,900 And after that, it's going to be destroyed 574 00:27:18,900 --> 00:27:20,150 and garbage collected as well. 575 00:27:20,150 --> 00:27:24,310 So at the point when your activity is destroyed, 576 00:27:24,310 --> 00:27:27,340 it's not going to be recreated it again. 577 00:27:27,340 --> 00:27:30,980 Your ViewModel is gone as well. 578 00:27:30,980 --> 00:27:37,970 So let's quickly make our sample in ViewModel. 579 00:27:37,970 --> 00:27:40,900 So it starts with instantiating-- with creation 580 00:27:40,900 --> 00:27:43,270 of ViewModel class. 581 00:27:43,270 --> 00:27:47,860 We want to cache for user data to create a fill for that. 582 00:27:47,860 --> 00:27:50,680 We agree our activity needs to access this LiveData, 583 00:27:50,680 --> 00:27:52,450 so we create a getter for this. 584 00:27:52,450 --> 00:27:55,960 And finally, getter is extremely straightforward. 585 00:27:55,960 --> 00:27:59,530 If we already requested the data, we just return it. 586 00:27:59,530 --> 00:28:04,780 If the data is now, we'll request it from a web service 587 00:28:04,780 --> 00:28:06,580 and return it. 588 00:28:06,580 --> 00:28:07,422 Fine. 589 00:28:07,422 --> 00:28:08,880 We had [INAUDIBLE] on our activity. 590 00:28:08,880 --> 00:28:12,580 Now we need to get this LiveData from ViewModel. 591 00:28:12,580 --> 00:28:18,370 To get it, we need to create to get ViewModel somehow. 592 00:28:18,370 --> 00:28:19,450 So this is how we do it. 593 00:28:19,450 --> 00:28:21,970 Let's take a precise look at it. 594 00:28:21,970 --> 00:28:25,000 First of all, we need to get ViewModel provider object. 595 00:28:25,000 --> 00:28:27,250 This is an object which is associated 596 00:28:27,250 --> 00:28:28,570 with a fragment or an activity. 597 00:28:28,570 --> 00:28:34,270 It knows how to get already existing ViewModel from it 598 00:28:34,270 --> 00:28:36,740 or how to create a new one. 599 00:28:36,740 --> 00:28:39,250 If there is no existing ViewModel. 600 00:28:39,250 --> 00:28:44,650 After that, we request our myActivity ViewModel, 601 00:28:44,650 --> 00:28:48,617 and later everything is quite simple. 602 00:28:48,617 --> 00:28:49,450 We get the userData. 603 00:28:49,450 --> 00:28:54,730 We observe it to update the UI. 604 00:28:54,730 --> 00:28:59,860 So what are the rules of usage of ViewModel? 605 00:28:59,860 --> 00:29:04,660 So ViewModel manages the data for the UI. 606 00:29:04,660 --> 00:29:08,290 It means that it speaks with business 607 00:29:08,290 --> 00:29:11,510 parts of your application to retrieve the data. 608 00:29:11,510 --> 00:29:15,470 So it may be a repository pattern or any other pattern 609 00:29:15,470 --> 00:29:17,890 that they use. 610 00:29:17,890 --> 00:29:22,450 It also, it's for its user modifications 611 00:29:22,450 --> 00:29:24,140 back to these components. 612 00:29:24,140 --> 00:29:26,720 And now a good case for ViewModel 613 00:29:26,720 --> 00:29:30,730 is acting as a communication layer between fragments 614 00:29:30,730 --> 00:29:32,530 in one activity. 615 00:29:32,530 --> 00:29:36,490 And Yigit will speak about this later. 616 00:29:36,490 --> 00:29:40,840 But prior to this, things that you must not 617 00:29:40,840 --> 00:29:42,560 do in your ViewModel. 618 00:29:42,560 --> 00:29:46,580 So first of all, you must not access 619 00:29:46,580 --> 00:29:51,870 views and any other UI- related entities. 620 00:29:51,870 --> 00:29:54,670 The reason for that, they are going 621 00:29:54,670 --> 00:29:57,010 to be created during configuration change. 622 00:29:57,010 --> 00:30:02,400 If you try to use them, you will ever use stale data from there, 623 00:30:02,400 --> 00:30:05,250 ever to leak them. 624 00:30:05,250 --> 00:30:09,230 That's going to finish bad. 625 00:30:09,230 --> 00:30:12,280 And it's fragmented or activity's job 626 00:30:12,280 --> 00:30:17,110 to bind the data which you will get from a ViewModel 627 00:30:17,110 --> 00:30:21,260 with actual UI, text use, buttons. 628 00:30:21,260 --> 00:30:23,190 I don't know what else. 629 00:30:23,190 --> 00:30:26,590 And one more thing, there are sources 630 00:30:26,590 --> 00:30:31,120 which sound more harmless like strings or drawable, 631 00:30:31,120 --> 00:30:33,790 and you may think, I may cash it here. 632 00:30:33,790 --> 00:30:38,020 No, they depend on current configuration state of state 633 00:30:38,020 --> 00:30:38,800 as well. 634 00:30:38,800 --> 00:30:43,360 So yes, right now you may have just one resource 635 00:30:43,360 --> 00:30:46,540 for every configuration, but later, you 636 00:30:46,540 --> 00:30:49,870 will add in the same resource for a different configuration. 637 00:30:49,870 --> 00:30:54,010 You will easily forget to update your ViewModel. 638 00:30:54,010 --> 00:30:58,540 And you may not notice this, but your users 639 00:30:58,540 --> 00:31:00,250 will see the invalid UI. 640 00:31:00,250 --> 00:31:02,230 And this is just ugly. 641 00:31:02,230 --> 00:31:06,970 And now Yigit will speak about Inter Fragment communications. 642 00:31:06,970 --> 00:31:10,510 643 00:31:10,510 --> 00:31:12,270 YIGIT BOYAR: So I want to talk about one 644 00:31:12,270 --> 00:31:16,050 of my favorite features about ViewModel, 645 00:31:16,050 --> 00:31:19,020 which is communicating between multiple fragments 646 00:31:19,020 --> 00:31:21,980 of the same activity. 647 00:31:21,980 --> 00:31:25,200 It's good that UI like this, like the Gmail on the tablet 648 00:31:25,200 --> 00:31:29,500 where on the left side you pick an email and on the right side, 649 00:31:29,500 --> 00:31:31,860 it shows the contents of the email. 650 00:31:31,860 --> 00:31:34,560 Now usually you will implement this as a fragment 651 00:31:34,560 --> 00:31:37,940 on the left which picks something from the list, 652 00:31:37,940 --> 00:31:39,780 and another fragment on the right, which 653 00:31:39,780 --> 00:31:42,960 shows how to show the contents of an email 654 00:31:42,960 --> 00:31:45,330 so that if you're on the phone you can reuse the same 655 00:31:45,330 --> 00:31:48,150 fragments but separate from each other. 656 00:31:48,150 --> 00:31:52,170 Now if you ever tried to write a UI like this, if you ever 657 00:31:52,170 --> 00:31:55,105 tried to make these two fragments talk to each other, 658 00:31:55,105 --> 00:31:56,220 it's a pain in the neck. 659 00:31:56,220 --> 00:31:57,240 It's very, very hard. 660 00:31:57,240 --> 00:31:59,510 Like you need to create an interface. 661 00:31:59,510 --> 00:32:01,530 But then what if one fragment gets 662 00:32:01,530 --> 00:32:03,540 created before the other one. 663 00:32:03,540 --> 00:32:05,940 An activity needs to talk to each other. 664 00:32:05,940 --> 00:32:07,931 Or like when the activities are restored, 665 00:32:07,931 --> 00:32:09,430 you don't really know which fragment 666 00:32:09,430 --> 00:32:11,340 will be restored first. 667 00:32:11,340 --> 00:32:14,880 It is really hard to manage this state. 668 00:32:14,880 --> 00:32:21,020 But we can actually solve this very elegantly using ViewModel. 669 00:32:21,020 --> 00:32:23,930 So let's say so these two families actually want 670 00:32:23,930 --> 00:32:26,390 to talk about a selected email. 671 00:32:26,390 --> 00:32:29,060 This is the information they want to share. 672 00:32:29,060 --> 00:32:30,950 So let's put it inside a ViewModel 673 00:32:30,950 --> 00:32:33,920 and we are going to call this shared ViewModel. 674 00:32:33,920 --> 00:32:36,130 So it has a mutable LiveData inside it 675 00:32:36,130 --> 00:32:41,430 which you call selected, and it provides two very simple APIs. 676 00:32:41,430 --> 00:32:45,410 The first one says, set the select email to this email. 677 00:32:45,410 --> 00:32:49,610 Another one says, get the selected email as a LiveData. 678 00:32:49,610 --> 00:32:52,510 It's a really simple ViewModel. 679 00:32:52,510 --> 00:32:56,030 But now once we have this, let's go back to our fragments 680 00:32:56,030 --> 00:32:58,260 and see how we can use this. 681 00:32:58,260 --> 00:33:00,920 So inside the content fragment, which is the one 682 00:33:00,920 --> 00:33:03,650 that wants to display the contents of the email. 683 00:33:03,650 --> 00:33:07,550 It wants to know when the selected email changes. 684 00:33:07,550 --> 00:33:09,930 So we're going to go-- so we have already seen this. 685 00:33:09,930 --> 00:33:12,470 You can go to ViewModel providers class 686 00:33:12,470 --> 00:33:15,230 and get the ViewModel providers of this fragment. 687 00:33:15,230 --> 00:33:19,170 But we actually want ViewModel not from this fragment, 688 00:33:19,170 --> 00:33:21,330 we want it from our activity. 689 00:33:21,330 --> 00:33:25,480 So all you have to do tell it to do it from your activity. 690 00:33:25,480 --> 00:33:28,520 Now it's going to return your ViewModel in the activity 691 00:33:28,520 --> 00:33:33,140 scope, and I will say, get for the shared ViewModel. 692 00:33:33,140 --> 00:33:35,770 Now, the very first time one of the fragments called this, 693 00:33:35,770 --> 00:33:37,460 we are going to create a new one. 694 00:33:37,460 --> 00:33:39,520 When the other fragment comes alive, 695 00:33:39,520 --> 00:33:42,830 it's going to receive the same ViewModel instance. 696 00:33:42,830 --> 00:33:44,100 And I will do the same thing. 697 00:33:44,100 --> 00:33:46,650 So this one says, get the selected email. 698 00:33:46,650 --> 00:33:48,662 Start observing on it. 699 00:33:48,662 --> 00:33:50,540 Really similarly, in the select fragment 700 00:33:50,540 --> 00:33:54,500 which was the one on the left by user pics and email, 701 00:33:54,500 --> 00:33:57,410 we get the same ViewModel. 702 00:33:57,410 --> 00:34:00,680 And whenever the user selects an email from the list, 703 00:34:00,680 --> 00:34:03,080 we just call the ViewModel- related method 704 00:34:03,080 --> 00:34:05,120 to change the selected email. 705 00:34:05,120 --> 00:34:08,239 Now these two fragments talking to each other 706 00:34:08,239 --> 00:34:10,710 without actually talking to each other. 707 00:34:10,710 --> 00:34:13,730 How does this really happen? 708 00:34:13,730 --> 00:34:15,380 So if we go back to our UI. 709 00:34:15,380 --> 00:34:18,679 So we have the selector on the left, the content on the right. 710 00:34:18,679 --> 00:34:21,320 But if you look at the details, actually both of these 711 00:34:21,320 --> 00:34:23,060 are talking to a shared ViewModel. 712 00:34:23,060 --> 00:34:25,040 They never talk to each other. 713 00:34:25,040 --> 00:34:28,580 The video of this solution is that if you're on the phone, 714 00:34:28,580 --> 00:34:31,280 let's say one fragment replaces the other one, 715 00:34:31,280 --> 00:34:33,080 there's no room for error. 716 00:34:33,080 --> 00:34:35,270 Like the fragment still talks to a ViewModel. 717 00:34:35,270 --> 00:34:37,370 ViewModels always that nothing will crash. 718 00:34:37,370 --> 00:34:39,770 They don't even care the other one is there. 719 00:34:39,770 --> 00:34:42,810 720 00:34:42,810 --> 00:34:45,349 Okay, so this is a lot of information, 721 00:34:45,349 --> 00:34:47,670 and there's further details about how 722 00:34:47,670 --> 00:34:49,170 these life cycles work. 723 00:34:49,170 --> 00:34:51,330 We really spent a lot of time to make 724 00:34:51,330 --> 00:34:55,260 these handle most common used cases on Android. 725 00:34:55,260 --> 00:34:58,620 So we come in just the first trade out. 726 00:34:58,620 --> 00:35:03,150 You could try it now, in [INAUDIBLE]. 727 00:35:03,150 --> 00:35:05,850 Please check out all of the architecture components. 728 00:35:05,850 --> 00:35:08,640 These are things that actually work very well together. 729 00:35:08,640 --> 00:35:11,070 We have an architecture guide which shows you 730 00:35:11,070 --> 00:35:15,330 how to use these things together to write a good application. 731 00:35:15,330 --> 00:35:16,980 And also check our code labs. 732 00:35:16,980 --> 00:35:20,490 We have code lab sections that will give you a first glimpse 733 00:35:20,490 --> 00:35:23,841 of how LifeCycles work. 734 00:35:23,841 --> 00:35:24,340 Thank you 735 00:35:24,340 --> 00:35:26,815 [APPLAUSE] 736 00:35:26,815 --> 00:35:29,055 [MUSIC PLAYING] 737 00:35:29,055 --> 00:00:00,000 |
1 00:00:00,000 --> 00:00:06,201 [ИГРАЕТ МУЗЫКА] 2 00:00:06,201 --> 00:00:09,380 СЕРГЕЙ ВАСИЛИНЕЦ: Доброе утро всем!. 3 00:00:09,380 --> 00:00:10,130 Меня зовут Сергей 4 00:00:10,130 --> 00:00:12,620 Это Adam и Yigit, они сегодня со мной, 5 00:00:12,620 --> 00:00:15,780 и мы поговорим о проблемах жизненного цикла. 6 00:00:15,780 --> 00:00:21,240 Возможно, многие из вас присутствовали вчера, 7 00:00:21,240 --> 00:00:24,670 когда Yigit представил новые архитектурные компоненты. 8 00:00:24,670 --> 00:00:27,550 Он представил LiveData, ViewModel, новую ORM 9 00:00:27,550 --> 00:00:28,540 называемую Room. 10 00:00:28,540 --> 00:00:31,900 И сегодня мы будем говорить о жизненном цикле из 11 00:00:31,900 --> 00:00:34,990 парадигмы архитектурных компонентов. 12 00:00:34,990 --> 00:00:37,715 Поэтому мы снова поговорим о LiveData и ViewModel. 13 00:00:37,715 --> 00:00:41,140 Мы поговорим о преимуществах жизненного цикла и о том, на каких 14 00:00:41,140 --> 00:00:45,210 библиотеках он основывается. 15 00:00:45,210 --> 00:00:49,150 Но мы затронем много деталей. 16 00:00:49,150 --> 00:00:51,890 У нас будут некоторые аргументы в пользу наших решений. 17 00:00:51,890 --> 00:00:56,360 И, если вы были на вчерашней сессии, вам будет все еще интересно. 18 00:00:56,360 --> 00:00:57,900 Но даже если вы не присутствовали вчера, мы 19 00:00:57,900 --> 00:00:59,600 заново расскажем обо всех этих вещах 20 00:00:59,600 --> 00:01:03,370 так что вам будет все понятно. 21 00:01:03,370 --> 00:01:07,480 Ну, давайте посмотрим что у нас есть. 22 00:01:07,480 --> 00:01:11,280 Сегодня у нас Activity по частям. 23 00:01:11,280 --> 00:01:14,300 Я начну стого, что длинно, но с того, где 24 00:01:14,300 --> 00:01:17,330 десятки и десятки строк. 25 00:01:17,330 --> 00:01:22,190 И эти строки результат очень естественного процесса. 26 00:01:22,190 --> 00:01:24,690 Сервисы Google play попросили зарегистрировать их 27 00:01:24,690 --> 00:01:25,670 в onStart методах. 28 00:01:25,670 --> 00:01:29,620 Ваши компоненты должны знать о событиях жизненного цикла, 29 00:01:29,620 --> 00:01:34,640 поэтому вам нужно получить их в каком-либо API. 30 00:01:34,640 --> 00:01:38,100 И соответственно, в onStop методе, 31 00:01:38,100 --> 00:01:42,530 вы должны вызвать все методы-остановки, 32 00:01:42,530 --> 00:01:44,900 и тогда очень легко забыть о каком-либо из них. 33 00:01:44,900 --> 00:01:46,880 И в результате утечка. 34 00:01:46,880 --> 00:01:51,950 И это приведет к растрате батареи пользователя, 35 00:01:51,950 --> 00:01:54,920 и ваше приложение понравится ему немного меньше. 36 00:01:54,920 --> 00:01:58,190 И это, возможно, нормально для них, но мы не думаем, что это хорошо. 37 00:01:58,190 --> 00:02:02,180 И они думают, что ответ в этой ситуации - это 38 00:02:02,180 --> 00:02:04,130 представление жизненного цикла осведомленным о компонентах. 39 00:02:04,130 --> 00:02:06,770 Компоненты, которые взаимодействуют с жизненным циклом. 40 00:02:06,770 --> 00:02:08,538 И первый щаг в этом r> направлении - представление 41 00:02:08,538 --> 00:02:11,750 жизненного цикла как объекта первого класса. 42 00:02:11,750 --> 00:02:13,550 Итак, это очень простой объект, который отвечает на 43 00:02:13,550 --> 00:02:17,370 вопрос, какое состояние сейчас? 44 00:02:17,370 --> 00:02:19,130 И уведомляет вас о новых событиях. И тогда 45 00:02:19,130 --> 00:02:22,340 никакая особенность не важна но звучит нелепо прямо сейчас, 46 00:02:22,340 --> 00:02:26,060 события и состояния - разные вещи. 47 00:02:26,060 --> 00:02:28,540 Вот, что я имею в виду. 48 00:02:28,540 --> 00:02:31,610 Ваша Activity создается в инициализированном состоянии. 49 00:02:31,610 --> 00:02:37,965 И все этапы создания проходят очень регулярно. 50 00:02:37,965 --> 00:02:39,680 OnCreate(), создание состояния. 51 00:02:39,680 --> 00:02:42,460 OnStart, старт состояния, то же самое для resume. 52 00:02:42,460 --> 00:02:45,070 Но дорога назад немного более интересная. 53 00:02:45,070 --> 00:02:48,920 So onPause event, leads you from a resume state 54 00:02:48,920 --> 00:02:50,480 back to a starting state. 55 00:02:50,480 --> 00:02:53,490 Not some new pause state, or something like that. 56 00:02:53,490 --> 00:02:57,870 And the reason for this is from a system perspective, 57 00:02:57,870 --> 00:03:01,880 the states after onPause event and onStart event are the same 58 00:03:01,880 --> 00:03:05,790 because the sets of the actions that you are allowed to do 59 00:03:05,790 --> 00:03:07,010 is the same. 60 00:03:07,010 --> 00:03:11,960 And the same is true for onStop and Creative state. 61 00:03:11,960 --> 00:03:14,350 And last event is onDestroy. 62 00:03:14,350 --> 00:03:18,390 It's pretty straightforward. 63 00:03:18,390 --> 00:03:20,150 It brings it to destroy state. 64 00:03:20,150 --> 00:03:21,730 Your activity is destroyed. 65 00:03:21,730 --> 00:03:25,720 It's going to be thrown away and garbage collected. 66 00:03:25,720 --> 00:03:28,020 So let's make our component LifeCycle aware. 67 00:03:28,020 --> 00:03:29,390 That's super straightforward. 68 00:03:29,390 --> 00:03:32,780 We take it with LifeCycle observer interface, 69 00:03:32,780 --> 00:03:34,350 accepted interface. 70 00:03:34,350 --> 00:03:40,320 To get the actual events, we add annotation and pass the events 71 00:03:40,320 --> 00:03:43,200 that we are interested in, you can pass multiple events 72 00:03:43,200 --> 00:03:43,950 if you want to. 73 00:03:43,950 --> 00:03:48,180 The last step is to add ourselves as an observer. 74 00:03:48,180 --> 00:03:53,910 And we may have a potential problem here. 75 00:03:53,910 --> 00:03:57,810 What if the activity is already started at this point? 76 00:03:57,810 --> 00:04:02,730 Does this mean that we are going to receive onStop event, 77 00:04:02,730 --> 00:04:05,970 and and we didn't receive onStart. 78 00:04:05,970 --> 00:04:09,540 And our component probably is not ready for this. 79 00:04:09,540 --> 00:04:12,570 But it took care of it, and we bring 80 00:04:12,570 --> 00:04:14,412 the observer to correct state. 81 00:04:14,412 --> 00:04:15,370 So what does this mean? 82 00:04:15,370 --> 00:04:17,670 Let's take this example, which I just discussed. 83 00:04:17,670 --> 00:04:20,610 From activity perspective onStart and onCreate 84 00:04:20,610 --> 00:04:26,250 create already happened, and after that we add an observer. 85 00:04:26,250 --> 00:04:31,740 But observer will still receive onCreate and onStart events 86 00:04:31,740 --> 00:04:34,950 immediately when they were registered. 87 00:04:34,950 --> 00:04:38,130 So let's take one step further. 88 00:04:38,130 --> 00:04:39,870 OnResume, same situation. 89 00:04:39,870 --> 00:04:41,400 Resume state will bring to resume 90 00:04:41,400 --> 00:04:45,550 state we got an onResume event in addition to onCreate 91 00:04:45,550 --> 00:04:46,610 and onStart. 92 00:04:46,610 --> 00:04:48,660 A bit more interesting situation, 93 00:04:48,660 --> 00:04:54,590 onPause In this situation, we are in a start state as well as 94 00:04:54,590 --> 00:04:55,830 we learned. 95 00:04:55,830 --> 00:04:59,060 So we bring the oberserver to the correct state 96 00:04:59,060 --> 00:05:00,030 which is start. 97 00:05:00,030 --> 00:05:04,040 So it's a similar situation as we had one minute ago. 98 00:05:04,040 --> 00:05:06,930 Observer will receive onCreate and onStart events, 99 00:05:06,930 --> 00:05:09,090 and that's it. 100 00:05:09,090 --> 00:05:13,460 So we don't have a problem in this code. 101 00:05:13,460 --> 00:05:17,240 So how to get this magical lifecycle object? 102 00:05:17,240 --> 00:05:20,940 We have this interface which is super simple, 103 00:05:20,940 --> 00:05:25,060 but this probably doesn't help much right now. 104 00:05:25,060 --> 00:05:26,580 And the actual question is who are 105 00:05:26,580 --> 00:05:29,600 LifeCycle owners out of box. 106 00:05:29,600 --> 00:05:34,310 And the answer in this question is support library fragments 107 00:05:34,310 --> 00:05:35,630 and support activities. 108 00:05:35,630 --> 00:05:40,140 But unfortunately, this is true only in the bright future. 109 00:05:40,140 --> 00:05:44,300 And right now we have LifeCycle activity 110 00:05:44,300 --> 00:05:46,040 and LifeCycle fragment. 111 00:05:46,040 --> 00:05:49,520 But at the point of 1.0 release, we 112 00:05:49,520 --> 00:05:53,720 will merge our library to support libraries so you 113 00:05:53,720 --> 00:05:56,070 don't have to use them later. 114 00:05:56,070 --> 00:05:59,400 And now Adam will speak about some key differences 115 00:05:59,400 --> 00:06:02,242 between fragment and LifeCyle observers 116 00:06:02,242 --> 00:06:04,200 ADAM POWELL: So if you've been following along, 117 00:06:04,200 --> 00:06:06,616 you probably recognize some similarities with the fragment 118 00:06:06,616 --> 00:06:07,950 API in this as well. 119 00:06:07,950 --> 00:06:10,850 So at this point we've got these two different components. 120 00:06:10,850 --> 00:06:12,480 Which one do you use? 121 00:06:12,480 --> 00:06:14,870 Well, as the slides are already spoiling for you, 122 00:06:14,870 --> 00:06:17,594 this really isn't an either- or question. 123 00:06:17,594 --> 00:06:20,010 One of these things doesn't necessarily replace the other. 124 00:06:20,010 --> 00:06:22,040 And here's why. 125 00:06:22,040 --> 00:06:25,830 Fragments, on one hand, that everybody knows and loves, 126 00:06:25,830 --> 00:06:28,190 are statefully managed and recreated 127 00:06:28,190 --> 00:06:32,030 after either a process death, an activity recreation, 128 00:06:32,030 --> 00:06:35,630 or recreation of any hosts that you have the fragment within. 129 00:06:35,630 --> 00:06:37,760 Fragments manage views and also interact 130 00:06:37,760 --> 00:06:39,620 with the navigation stack, which are 131 00:06:39,620 --> 00:06:42,230 things that are firmly out of scope of what LifeCycle 132 00:06:42,230 --> 00:06:43,880 observers are meant to do. 133 00:06:43,880 --> 00:06:45,740 Instead, LifeCycle observers are meant 134 00:06:45,740 --> 00:06:47,930 to enable more granular factoring of your code, 135 00:06:47,930 --> 00:06:50,360 whether you're in an activity or a fragment. 136 00:06:50,360 --> 00:06:51,110 They're stateless. 137 00:06:51,110 --> 00:06:53,570 So that means that they must be registered each time 138 00:06:53,570 --> 00:06:54,770 the owner is recreated. 139 00:06:54,770 --> 00:06:56,186 We're not going to try to recreate 140 00:06:56,186 --> 00:06:57,290 these magically for you. 141 00:06:57,290 --> 00:06:59,150 They don't have any concept of instant state 142 00:06:59,150 --> 00:07:00,780 that they carry around with them. 143 00:07:00,780 --> 00:07:02,510 So these are meant to be very, very lightweight, 144 00:07:02,510 --> 00:07:04,968 so that you don't have a whole lot of additional management 145 00:07:04,968 --> 00:07:06,170 overhead. 146 00:07:06,170 --> 00:07:09,470 And last, there's no relation to the viewer navigation 147 00:07:09,470 --> 00:07:10,010 management. 148 00:07:10,010 --> 00:07:12,470 These really are meant to be very tightly 149 00:07:12,470 --> 00:07:16,330 scoped, isolated components. 150 00:07:16,330 --> 00:07:17,950 So they can really help everyone. 151 00:07:17,950 --> 00:07:21,040 It means that it's much simpler to integrate libraries 152 00:07:21,040 --> 00:07:23,860 with your code, as long as those libraries have provided 153 00:07:23,860 --> 00:07:26,124 LifeCycle observer aware components. 154 00:07:26,124 --> 00:07:28,540 It means that you can break up those really large fragment 155 00:07:28,540 --> 00:07:31,300 or activity classes to make them much simpler to understand 156 00:07:31,300 --> 00:07:32,440 for a reader. 157 00:07:32,440 --> 00:07:35,200 And you can provide much more granular guarantees 158 00:07:35,200 --> 00:07:38,660 around what operations are valid at any given point in time. 159 00:07:38,660 --> 00:07:41,860 You can make it so that if an operation happens then 160 00:07:41,860 --> 00:07:44,050 you're guaranteed to be in a correct state 161 00:07:44,050 --> 00:07:45,130 when something is called. 162 00:07:45,130 --> 00:07:48,060 163 00:07:48,060 --> 00:07:50,685 So LifeCycle owner as already introduced 164 00:07:50,685 --> 00:07:51,900 is just an interface. 165 00:07:51,900 --> 00:07:53,630 Anyone can implement this. 166 00:07:53,630 --> 00:07:55,680 This means that you can improve testability 167 00:07:55,680 --> 00:07:56,802 by creating your own. 168 00:07:56,802 --> 00:07:59,010 You can create your own sort of fragment-like library 169 00:07:59,010 --> 00:08:01,170 implementations if you feel so inclined. 170 00:08:01,170 --> 00:08:03,330 But you can also create composite life cycles. 171 00:08:03,330 --> 00:08:06,780 Life cycles that span across other smaller lifecycle 172 00:08:06,780 --> 00:08:08,010 definitions. 173 00:08:08,010 --> 00:08:10,710 So you can answer questions like, is my app visible? 174 00:08:10,710 --> 00:08:12,750 So this is a really common composite lifecycle 175 00:08:12,750 --> 00:08:15,000 that many of you may be interested in. 176 00:08:15,000 --> 00:08:17,160 It lets you do things like session management 177 00:08:17,160 --> 00:08:19,530 to track a particular session across perhaps 178 00:08:19,530 --> 00:08:23,100 some sort of a flow or a series of logged 179 00:08:23,100 --> 00:08:24,870 in versus logged out events. 180 00:08:24,870 --> 00:08:29,020 And it may help you with analytics as well. 181 00:08:29,020 --> 00:08:32,280 So we have the process LifeCycle owner as kind of a component 182 00:08:32,280 --> 00:08:35,350 that I think a lot of you will be interested in for this. 183 00:08:35,350 --> 00:08:39,058 It's the composite lifecycle of all the activities in your app. 184 00:08:39,058 --> 00:08:41,009 So there's no configuration changes to handle, 185 00:08:41,010 --> 00:08:44,440 because we're not going to be dealing with those from these. 186 00:08:44,440 --> 00:08:46,350 The process LifeCycle owner just stays 187 00:08:46,350 --> 00:08:48,000 alive through the whole process. 188 00:08:48,000 --> 00:08:50,041 But that also means that you don't get state risk 189 00:08:50,041 --> 00:08:52,660 restoration after process death like we mentioned earlier. 190 00:08:52,660 --> 00:08:54,600 So that means that you don't have 191 00:08:54,600 --> 00:08:56,905 to handle saving and restoring that state 192 00:08:56,905 --> 00:08:59,280 but at the same time, you need to remember to re-register 193 00:08:59,280 --> 00:09:02,199 these process lifecycle-based observers if that's something 194 00:09:02,199 --> 00:09:03,240 that you're working with. 195 00:09:03,240 --> 00:09:05,750 196 00:09:05,750 --> 00:09:09,110 So many indirect components provide a lot 197 00:09:09,110 --> 00:09:11,330 of deep plumbing layers for things 198 00:09:11,330 --> 00:09:13,790 that you can plug into and work with. 199 00:09:13,790 --> 00:09:15,800 But a lot of times we've kind of omitted 200 00:09:15,800 --> 00:09:17,720 the idea of higher level components that 201 00:09:17,720 --> 00:09:20,210 make use of that plumbing so that you can just plug 202 00:09:20,210 --> 00:09:21,280 play and go. 203 00:09:21,280 --> 00:09:24,300 So do we have anything more high level than the bare events 204 00:09:24,300 --> 00:09:25,530 and states here? 205 00:09:25,530 --> 00:09:26,800 YIGIT BOYAR: Maybe we do. 206 00:09:26,800 --> 00:09:27,760 I will show you. 207 00:09:27,760 --> 00:09:28,870 ADAM POWELL: Great 208 00:09:28,870 --> 00:09:30,530 YIGIT BOYAR: Thanks, Adam. 209 00:09:30,530 --> 00:09:33,680 So it's so nice now you can observe 210 00:09:33,680 --> 00:09:37,310 a LifeCycle is well-defined, is a first class citizen. 211 00:09:37,310 --> 00:09:40,530 But you still need to deal with these things. 212 00:09:40,530 --> 00:09:44,780 And we told like, there's some common LifeCycle problems 213 00:09:44,780 --> 00:09:47,100 that we should be able to solve with this component. 214 00:09:47,100 --> 00:09:48,860 So we'll look at the problems that people 215 00:09:48,860 --> 00:09:51,740 are having, and this was probably 216 00:09:51,740 --> 00:09:54,110 the most major problem we've been seeing, 217 00:09:54,110 --> 00:09:56,320 the untimely UI updates. 218 00:09:56,320 --> 00:09:58,920 It's like your activity receives a callback, 219 00:09:58,920 --> 00:10:00,530 but the activity's already stopped. 220 00:10:00,530 --> 00:10:03,050 They tried to start a new activity and crashes. 221 00:10:03,050 --> 00:10:06,010 Or it tries to add a fragment and crashes. 222 00:10:06,010 --> 00:10:09,410 If an activity or a fragment is stopped, 223 00:10:09,410 --> 00:10:12,317 there is no reason to update that activity. 224 00:10:12,317 --> 00:10:13,400 You don't want to do that. 225 00:10:13,400 --> 00:10:16,190 If the activity happens to become visible again, then 226 00:10:16,190 --> 00:10:17,480 you want to do it. 227 00:10:17,480 --> 00:10:20,480 So we realized that this is a very common problem, 228 00:10:20,480 --> 00:10:23,990 and we wanted to solve this with a higher level component which 229 00:10:23,990 --> 00:10:26,060 we call LiveData. 230 00:10:26,060 --> 00:10:29,780 When we look at the LiveData in detail, 231 00:10:29,780 --> 00:10:32,840 it's actually an observable data holder. 232 00:10:32,840 --> 00:10:35,180 It just holds on to some information 233 00:10:35,180 --> 00:10:36,490 that you can observe. 234 00:10:36,490 --> 00:10:38,270 Now the difference between LiveData 235 00:10:38,270 --> 00:10:41,225 and your other observables in data mining or RxJava 236 00:10:41,225 --> 00:10:45,350 or whatever, is that LiveData is LifeCycle aware. 237 00:10:45,350 --> 00:10:48,020 It knows about Android life cycles, 238 00:10:48,020 --> 00:10:50,030 and when you want to observe a LiveData, 239 00:10:50,030 --> 00:10:52,580 you can pass in this LifeCycle so that it 240 00:10:52,580 --> 00:10:54,480 can manage your subscription. 241 00:10:54,480 --> 00:10:57,210 The nice thing about LiveData that is that you observe, 242 00:10:57,210 --> 00:10:59,340 and that's all you do. 243 00:10:59,340 --> 00:11:00,860 So if we look at the usage example, 244 00:11:00,860 --> 00:11:02,210 let's say we have an activity. 245 00:11:02,210 --> 00:11:04,110 We receive a LiveData from somewhere. 246 00:11:04,110 --> 00:11:08,040 It doesn't really matter, and now we call observe on it. 247 00:11:08,040 --> 00:11:10,160 And when we are calling observe, we 248 00:11:10,160 --> 00:11:13,600 are passing this, which is the LiveData owner. 249 00:11:13,600 --> 00:11:14,780 That's all you need to say. 250 00:11:14,780 --> 00:11:18,770 I want to observe this LiveData within this LifeCycle. 251 00:11:18,770 --> 00:11:21,830 Which also means if this LifeCycle is gone, 252 00:11:21,830 --> 00:11:23,150 I don't want to observe it. 253 00:11:23,150 --> 00:11:26,550 Or if this LifeCycle is stopped, I don't want to receive events. 254 00:11:26,550 --> 00:11:30,466 255 00:11:30,466 --> 00:11:32,340 And then once you do this, that's all you do. 256 00:11:32,340 --> 00:11:34,410 You don't need to write onStart, onStop. 257 00:11:34,410 --> 00:11:37,870 We want Android to want to look more like this. 258 00:11:37,870 --> 00:11:40,040 You initialze things as more like find and forget. 259 00:11:40,040 --> 00:11:43,060 You initialize, and you're done. 260 00:11:43,060 --> 00:11:45,990 So let's look at what happens when our activity starts 261 00:11:45,990 --> 00:11:47,910 observing that LiveData. 262 00:11:47,910 --> 00:11:52,560 So onCreate, it called observe, it said LiveData is observable. 263 00:11:52,560 --> 00:11:54,630 And as soon as the activity starts, 264 00:11:54,630 --> 00:11:56,470 it starts receiving data changes. 265 00:11:56,470 --> 00:11:59,490 So whenever the LiveData value changes, 266 00:11:59,490 --> 00:12:01,950 we displace that event back to your observer 267 00:12:01,950 --> 00:12:03,530 inside the activity. 268 00:12:03,530 --> 00:12:05,450 It can also be a fragment. 269 00:12:05,450 --> 00:12:07,260 Let's say a user decides to rotate 270 00:12:07,260 --> 00:12:09,090 the activity at this moment. 271 00:12:09,090 --> 00:12:11,540 So you know that the activity will be stopped. 272 00:12:11,540 --> 00:12:13,320 And what happens at the same time, 273 00:12:13,320 --> 00:12:16,110 the LiveData happens to be updated. 274 00:12:16,110 --> 00:12:18,990 If that happens, we are not going to tell the activity 275 00:12:18,990 --> 00:12:22,590 about this change because there cannot be any reason for you 276 00:12:22,590 --> 00:12:27,210 to update the UI, because it already stopped. 277 00:12:27,210 --> 00:12:29,640 Similarly, if the activity is destroyed, 278 00:12:29,640 --> 00:12:31,980 we will automatically remove that subscription 279 00:12:31,980 --> 00:12:34,320 because that activity is gone. 280 00:12:34,320 --> 00:12:36,990 There is no reason to keep a reference back 281 00:12:36,990 --> 00:12:39,240 to that activity. 282 00:12:39,240 --> 00:12:41,010 Now we said the activity was rotating, 283 00:12:41,010 --> 00:12:42,630 so you know that Android is going 284 00:12:42,630 --> 00:12:44,880 to recreate that activity. 285 00:12:44,880 --> 00:12:48,270 And then we are observing the same LiveData back. 286 00:12:48,270 --> 00:12:49,985 As soon as that activity starts, it's 287 00:12:49,985 --> 00:12:53,190 going to receive last available data. 288 00:12:53,190 --> 00:12:57,720 So your UI is going to have the data before it gets a chance 289 00:12:57,720 --> 00:12:59,790 to draw. 290 00:12:59,790 --> 00:13:01,920 So similarly, I say the user hits 291 00:13:01,920 --> 00:13:05,330 the Home button, which means the activity will be stopped. 292 00:13:05,330 --> 00:13:08,700 Again, if the LiveData changes while the activity is stopped, 293 00:13:08,700 --> 00:13:10,840 it's not going to receive any events. 294 00:13:10,840 --> 00:13:14,010 Even if the data changes, we are not going to tell it. 295 00:13:14,010 --> 00:13:17,280 But as soon as if the user comes back to the application, 296 00:13:17,280 --> 00:13:19,510 we will give it the last available data. 297 00:13:19,510 --> 00:13:22,990 So this is why we call LiveData is not just a stream of events. 298 00:13:22,990 --> 00:13:26,910 It holds onto the data so that if any observer comes, 299 00:13:26,910 --> 00:13:30,430 it receives the last available value. 300 00:13:30,430 --> 00:13:33,620 And then eventually, the user backs out of that activity, 301 00:13:33,620 --> 00:13:37,830 and then we remove that subscription. 302 00:13:37,830 --> 00:13:40,730 You can also extend the LiveData class. 303 00:13:40,730 --> 00:13:45,950 Because LiveData provides two really handy callbacks. 304 00:13:45,950 --> 00:13:48,410 The first one is called onactive which means 305 00:13:48,410 --> 00:13:50,930 you have an active observer. 306 00:13:50,930 --> 00:13:52,580 Another one is called oninactive, 307 00:13:52,580 --> 00:13:54,370 which means you don't have any observers, 308 00:13:54,370 --> 00:13:56,450 so don't bother changing your value 309 00:13:56,450 --> 00:14:00,020 if it is something that you care about. 310 00:14:00,020 --> 00:14:03,800 You probably ask now what is an active observer? 311 00:14:03,800 --> 00:14:06,220 An active observer is an observer 312 00:14:06,220 --> 00:14:09,680 whose attached LifeCycle is started or resumed. 313 00:14:09,680 --> 00:14:12,890 So it's like a fragment that's currently visible to the user. 314 00:14:12,890 --> 00:14:15,380 If the fragment is on the back stack, 315 00:14:15,380 --> 00:14:16,660 the user is not seeing it. 316 00:14:16,660 --> 00:14:18,260 It stopped, so it's not active. 317 00:14:18,260 --> 00:14:22,430 There's no reason to do any work for that fragment. 318 00:14:22,430 --> 00:14:24,850 Let's see how we can take advantage of these named 319 00:14:24,850 --> 00:14:25,770 callbacks. 320 00:14:25,770 --> 00:14:28,270 We are going to create a new location LiveData 321 00:14:28,270 --> 00:14:31,190 class, which presents the location of something 322 00:14:31,190 --> 00:14:32,580 on the device. 323 00:14:32,580 --> 00:14:37,920 So we say this data holds an instance of a location. 324 00:14:37,920 --> 00:14:40,460 In cross-sector, we just get the location manager 325 00:14:40,460 --> 00:14:41,850 from the system service. 326 00:14:41,850 --> 00:14:43,670 There's nothing fancy here. 327 00:14:43,670 --> 00:14:47,210 We have a listener whenever the system server sends us 328 00:14:47,210 --> 00:14:50,830 any location, we just call setValue on us. 329 00:14:50,830 --> 00:14:51,530 This all you do. 330 00:14:51,530 --> 00:14:53,460 There is no LifeCycle handling here. 331 00:14:53,460 --> 00:14:56,120 You just call setValue, and LiveData takes 332 00:14:56,120 --> 00:14:57,710 care of handling the LifeCycle. 333 00:14:57,710 --> 00:15:00,080 And you may have any number of observers. 334 00:15:00,080 --> 00:15:02,450 It doesn't really matter. 335 00:15:02,450 --> 00:15:04,850 So we want to override onactive. 336 00:15:04,850 --> 00:15:07,340 The very first active observer comes. 337 00:15:07,340 --> 00:15:10,280 We want to start listening to the system service. 338 00:15:10,280 --> 00:15:14,300 Similarly, when the last active observer goes away, 339 00:15:14,300 --> 00:15:19,140 we want to stop observing the system service. 340 00:15:19,140 --> 00:15:21,800 Now if you look at that location LiveData class 341 00:15:21,800 --> 00:15:24,020 we just created in the previous example, let's look 342 00:15:24,020 --> 00:15:26,210 at the properties of that class. 343 00:15:26,210 --> 00:15:28,100 First of all, it is LifeCycle area. 344 00:15:28,100 --> 00:15:31,280 It knows when to start itself, when to stop itself. 345 00:15:31,280 --> 00:15:34,340 You just don't need to babysit it anymore. 346 00:15:34,340 --> 00:15:36,110 It is self-sufficient. 347 00:15:36,110 --> 00:15:37,140 You start it. 348 00:15:37,140 --> 00:15:39,480 You forget about it. 349 00:15:39,480 --> 00:15:40,470 It can be a singleton. 350 00:15:40,470 --> 00:15:42,620 Like all of the subscriptions are automatically 351 00:15:42,620 --> 00:15:43,850 managed for you. 352 00:15:43,850 --> 00:15:47,090 So if the data is logically singleton your codebase, 353 00:15:47,090 --> 00:15:50,030 you can make the LiveData instance singleton. 354 00:15:50,030 --> 00:15:51,710 So there's this thing where normally 355 00:15:51,710 --> 00:15:54,800 if you keep referencing an activity or a fragment 356 00:15:54,800 --> 00:15:57,720 from a certain context, that will be a big no no. 357 00:15:57,720 --> 00:16:00,350 But if you are using LiveData it is yes yes, 358 00:16:00,350 --> 00:16:05,340 because we manage the substitution for you. 359 00:16:05,340 --> 00:16:08,550 So you also don't need to subclass LiveData all the time. 360 00:16:08,550 --> 00:16:10,910 So if you just need an instance of it 361 00:16:10,910 --> 00:16:12,790 but you already have the value, you 362 00:16:12,790 --> 00:16:14,990 could use this mutable LiveData class, 363 00:16:14,990 --> 00:16:18,770 which comes inside the library that has a public setter. 364 00:16:18,770 --> 00:16:21,170 But usually when you are using this class, 365 00:16:21,170 --> 00:16:24,530 internally you will have it but the API you expose 366 00:16:24,530 --> 00:16:26,360 will just return a LiveData, because you 367 00:16:26,360 --> 00:16:28,370 don't want to expose the fact that anyone 368 00:16:28,370 --> 00:16:31,470 can set the value on it. 369 00:16:31,470 --> 00:16:34,920 Now when we were designing these LifeCycle components, 370 00:16:34,920 --> 00:16:38,730 the LiveData, see we spent a lot of time 371 00:16:38,730 --> 00:16:41,380 to get rid of one exception. 372 00:16:41,380 --> 00:16:43,350 This fragment exception that I-- 373 00:16:43,350 --> 00:16:50,520 [APPLAUSE] 374 00:16:50,520 --> 00:16:54,350 We really wanted to say, please, no more fragment transaction 375 00:16:54,350 --> 00:16:55,460 exceptions. 376 00:16:55,460 --> 00:16:58,570 So LiveData guarantees that if you received anywhere, 377 00:16:58,570 --> 00:17:00,910 you could run a fragment transaction. 378 00:17:00,910 --> 00:17:05,310 And to see how we are making it part of the history, 379 00:17:05,310 --> 00:17:10,118 I want to invite Adam back to explain it to us. 380 00:17:10,118 --> 00:17:11,539 ADAM POWELL: All right, so anyone 381 00:17:11,540 --> 00:17:13,205 who has received one of these exceptions 382 00:17:13,205 --> 00:17:15,289 realizes that it doesn't just come 383 00:17:15,290 --> 00:17:18,710 from trying to do something when you just completely stopped 384 00:17:18,710 --> 00:17:20,348 and you absolutely know it. 385 00:17:20,348 --> 00:17:21,889 These exceptions tend to come in when 386 00:17:21,890 --> 00:17:26,010 you get into very intricate, nested life cycles. 387 00:17:26,010 --> 00:17:28,910 So we wanted to make sure to be very thoughtful about defining 388 00:17:28,910 --> 00:17:34,190 how the LifeCycle observer callbacks are invoked and when. 389 00:17:34,190 --> 00:17:37,400 So in a case like this, what happens? 390 00:17:37,400 --> 00:17:42,120 You have defined handler for the stop event. 391 00:17:42,120 --> 00:17:44,872 So in the container your activity onStop, 392 00:17:44,872 --> 00:17:47,330 you want to make sure that you don't get an onChanged event 393 00:17:47,330 --> 00:17:48,770 after the onStop has happened. 394 00:17:48,770 --> 00:17:52,660 395 00:17:52,660 --> 00:17:54,570 But in order for that to happen, what 396 00:17:54,570 --> 00:17:56,490 needs to be true about when we actually 397 00:17:56,490 --> 00:18:00,030 invoke all of the onStop listeners 398 00:18:00,030 --> 00:18:02,610 that are attached to these observers. 399 00:18:02,610 --> 00:18:05,770 So we have to define a really strict order for this. 400 00:18:05,770 --> 00:18:09,420 So as we go through create and start and onResume, 401 00:18:09,420 --> 00:18:11,940 we know that we need to invoke the LifeCycle 402 00:18:11,940 --> 00:18:15,480 observers after the container event happens. 403 00:18:15,480 --> 00:18:18,090 So you know in your observer that everything 404 00:18:18,090 --> 00:18:20,461 about your LifeCycle owner has been configured. 405 00:18:20,461 --> 00:18:21,960 If you check any state about it, you 406 00:18:21,960 --> 00:18:25,397 know that you're already completely in that state. 407 00:18:25,397 --> 00:18:27,480 But that means something really special for coming 408 00:18:27,480 --> 00:18:29,470 back down the other direction. 409 00:18:29,470 --> 00:18:33,540 It means that when the activity starts to become paused, 410 00:18:33,540 --> 00:18:34,995 you want your LifeCycle observers 411 00:18:34,995 --> 00:18:36,870 to be able to shut down anything that they're 412 00:18:36,870 --> 00:18:39,060 doing before the activity does all of the work 413 00:18:39,060 --> 00:18:41,400 to actually become paused. 414 00:18:41,400 --> 00:18:42,810 Similar for stop. 415 00:18:42,810 --> 00:18:44,850 And this is where this becomes really 416 00:18:44,850 --> 00:18:47,220 important for the fragment transaction exception. 417 00:18:47,220 --> 00:18:49,260 You want to make sure that you're 418 00:18:49,260 --> 00:18:52,440 recording, that you're fully stopped before the fragment 419 00:18:52,440 --> 00:18:54,600 system goes through and flags everything 420 00:18:54,600 --> 00:18:58,180 as being completely locked out. 421 00:18:58,180 --> 00:19:01,410 So what that means is that the stop event of your LifeCycle 422 00:19:01,410 --> 00:19:04,770 observer will always be invoked before the activity onStop 423 00:19:04,770 --> 00:19:10,710 or before the full stop event for your container happens. 424 00:19:10,710 --> 00:19:13,260 So this seems really similar to some other libraries 425 00:19:13,260 --> 00:19:15,480 that some people may have seen in the past. 426 00:19:15,480 --> 00:19:16,600 Can you talk about that? 427 00:19:16,600 --> 00:19:22,530 SERGEI VASILINETC: Yes, when we create new observable pattern, 428 00:19:22,530 --> 00:19:26,220 nowadays this question is unavoidable. 429 00:19:26,220 --> 00:19:29,220 Is it another RxJava? 430 00:19:29,220 --> 00:19:32,490 And the answer to this question is, yes, 431 00:19:32,490 --> 00:19:34,740 because we want to promote a reactive programming 432 00:19:34,740 --> 00:19:37,980 model, especially when it comes to the relationship 433 00:19:37,980 --> 00:19:40,710 between your UI and the state [INAUDIBLE] UI. 434 00:19:40,710 --> 00:19:45,490 We want you to react on the changes of the state. 435 00:19:45,490 --> 00:19:48,300 So it means that it's a reactive programming model. 436 00:19:48,300 --> 00:19:51,000 But on the other hand, no. 437 00:19:51,000 --> 00:19:54,840 Because it's the LifeCycle aware out of box, 438 00:19:54,840 --> 00:19:57,930 as Yigit mentioned, and it's much easier. 439 00:19:57,930 --> 00:20:02,940 As many of you may know, the learning curve of RxJava 440 00:20:02,940 --> 00:20:04,560 is super steep. 441 00:20:04,560 --> 00:20:08,850 And if you have an Android learner curve, 442 00:20:08,850 --> 00:20:13,350 and after that we add RxJava learning curve on top of it, 443 00:20:13,350 --> 00:20:16,050 it becomes very hard to new people 444 00:20:16,050 --> 00:20:19,420 to start to develop on our platform. 445 00:20:19,420 --> 00:20:25,890 So we can't just say to them, oh let's go, just learn this, 446 00:20:25,890 --> 00:20:27,330 that's it. . 447 00:20:27,330 --> 00:20:32,310 No, but if you already learned RxJava, 448 00:20:32,310 --> 00:20:37,020 we don't expect you to migrate from it to our solution. 449 00:20:37,020 --> 00:20:41,280 Because you already passed the learning curve, 450 00:20:41,280 --> 00:20:45,960 you and your coworkers are comfortable with it, fine. 451 00:20:45,960 --> 00:20:48,190 We are totally fine with this. 452 00:20:48,190 --> 00:20:51,330 But one thing we ask you to do is to be sure 453 00:20:51,330 --> 00:20:53,920 that you manage LifeCycle. 454 00:20:53,920 --> 00:20:58,210 RxJava has common approaches to solve this. 455 00:20:58,210 --> 00:21:02,430 Be sure to use it and everything will be fine. 456 00:21:02,430 --> 00:21:09,885 But when you start a new app, I think this model is the best. 457 00:21:09,885 --> 00:21:15,010 The best is to start the project with LiveData, because it's 458 00:21:15,010 --> 00:21:17,310 simpler, it's faster, it's lightweight, 459 00:21:17,310 --> 00:21:20,270 it's well integrated with a framework. 460 00:21:20,270 --> 00:21:24,970 And if you feel like you love reacting programming a lot, 461 00:21:24,970 --> 00:21:28,480 you want to bring it not only to relation 462 00:21:28,480 --> 00:21:31,930 between UI and the state. 463 00:21:31,930 --> 00:21:33,430 You want to bring it to the business 464 00:21:33,430 --> 00:21:36,340 part of your application. 465 00:21:36,340 --> 00:21:41,070 Then you may consider the addition of RxJava, 466 00:21:41,070 --> 00:21:44,230 because it gives you more power. 467 00:21:44,230 --> 00:21:47,140 And we will actually help you to do that. 468 00:21:47,140 --> 00:21:51,790 We have this extension to our library, which 469 00:21:51,790 --> 00:21:55,780 gives a possibility to create LiveData from Publisher 470 00:21:55,780 --> 00:21:58,930 and create Publisher from LiveData. 471 00:21:58,930 --> 00:22:03,970 So this integration should be quite smooth. 472 00:22:03,970 --> 00:22:07,330 But I want to highlight a key difference between RxJava 473 00:22:07,330 --> 00:22:08,080 and LiveData. 474 00:22:08,080 --> 00:22:11,980 So as Yigit already said, LiveData 475 00:22:11,980 --> 00:22:13,870 is a holder and not a stream. 476 00:22:13,870 --> 00:22:17,320 So we have a reference to the last value, 477 00:22:17,320 --> 00:22:20,290 and observers immediately receive the last value when 478 00:22:20,290 --> 00:22:24,820 they start to observe LiveData. 479 00:22:24,820 --> 00:22:27,550 And now the big difference is a threading model. 480 00:22:27,550 --> 00:22:31,840 As you know, RxJava has a very sophisticated threading model. 481 00:22:31,840 --> 00:22:35,390 It's extremely powerful, but in most cases, 482 00:22:35,390 --> 00:22:37,610 you probably don't need it. 483 00:22:37,610 --> 00:22:40,360 And we have everything on the main thread. 484 00:22:40,360 --> 00:22:42,190 And the reason for this is we want 485 00:22:42,190 --> 00:22:47,150 to give you all these guarantees about when we will notify you 486 00:22:47,150 --> 00:22:50,740 about state changes. 487 00:22:50,740 --> 00:22:56,200 And we can't do this on a background thread. 488 00:22:56,200 --> 00:22:58,330 We have just the one exception. 489 00:22:58,330 --> 00:23:00,850 We have a post value method which 490 00:23:00,850 --> 00:23:03,720 just is a method which trampoline value 491 00:23:03,720 --> 00:23:07,725 from a background thread to the main thread and sets it there. 492 00:23:07,725 --> 00:23:08,770 It's super simple. 493 00:23:08,770 --> 00:23:11,400 So quick summary of what we have at this point. 494 00:23:11,400 --> 00:23:13,870 LiveData events, observable pattern 495 00:23:13,870 --> 00:23:16,460 which respects these events. 496 00:23:16,460 --> 00:23:20,090 But there is one big thing which is not covered yet. 497 00:23:20,090 --> 00:23:23,590 And this is how to handle onConfigurationChanges. 498 00:23:23,590 --> 00:23:28,690 In 2017, almost nine years after Android 499 00:23:28,690 --> 00:23:32,050 was first time released, we still discuss this question. 500 00:23:32,050 --> 00:23:34,090 And this is a totally legit question. 501 00:23:34,090 --> 00:23:38,290 And we hear it constantly from new Android developers. 502 00:23:38,290 --> 00:23:40,730 Many of you probably know whats the deal with it. 503 00:23:40,730 --> 00:23:44,770 But let's take a look at this oversimplified example, 504 00:23:44,770 --> 00:23:47,830 but it's still very vivid. 505 00:23:47,830 --> 00:23:50,050 So he wants to show this information 506 00:23:50,050 --> 00:23:52,060 about user and your activity. 507 00:23:52,060 --> 00:23:54,830 And you want to make some web service request. 508 00:23:54,830 --> 00:24:00,340 We will use LiveData to get this result. It's super simple. 509 00:24:00,340 --> 00:24:02,800 When the request is just started, it's empty. 510 00:24:02,800 --> 00:24:06,620 When the request response is received, 511 00:24:06,620 --> 00:24:11,740 we put it to LiveData as a value. 512 00:24:11,740 --> 00:24:14,070 And later we'll update our UI. 513 00:24:14,070 --> 00:24:19,917 We will notify the activity, and it will do everything it needs. 514 00:24:19,917 --> 00:24:22,250 So what happens if the activity is going to [INAUDIBLE]. 515 00:24:22,250 --> 00:24:25,750 We're going to make a call twice, 516 00:24:25,750 --> 00:24:28,560 and I hope that you don't call web service right 517 00:24:28,560 --> 00:24:29,740 into your activity. 518 00:24:29,740 --> 00:24:33,670 But you probably have some abstractions 519 00:24:33,670 --> 00:24:36,010 that does something like that, which 520 00:24:36,010 --> 00:24:41,040 goes to a network, which goes to caching and persistence 521 00:24:41,040 --> 00:24:43,030 storages. 522 00:24:43,030 --> 00:24:47,170 And all the separations are synchronized by nature. 523 00:24:47,170 --> 00:24:51,070 So communication of these components are synchronized. 524 00:24:51,070 --> 00:24:55,510 And you probably don't want to make these calls twice anyway. 525 00:24:55,510 --> 00:24:58,060 So what you want to do is to cache. 526 00:24:58,060 --> 00:25:01,470 This is our data, like in our example. 527 00:25:01,470 --> 00:25:04,480 And what are the ways today to do that? 528 00:25:04,480 --> 00:25:06,960 Well, one of a proposed way to do it 529 00:25:06,960 --> 00:25:10,570 is a Fragment.setRetainInstance, and Yigit 530 00:25:10,570 --> 00:25:12,340 can rant about this for hours. 531 00:25:12,340 --> 00:25:14,770 Unfortunately, we don't have time for this today. 532 00:25:14,770 --> 00:25:17,600 But I just say that the only effect 533 00:25:17,600 --> 00:25:19,900 that you have to run fragment transaction 534 00:25:19,900 --> 00:25:22,400 is terrifying for a lot of people. 535 00:25:22,400 --> 00:25:25,780 People go nuts and another possible way 536 00:25:25,780 --> 00:25:29,960 to solve this is loaders, but we don't fit here well as well. 537 00:25:29,960 --> 00:25:33,010 So we decided to tackle this problem once again 538 00:25:33,010 --> 00:25:35,230 and create ViewModel. 539 00:25:35,230 --> 00:25:36,030 So what is this? 540 00:25:36,030 --> 00:25:39,070 ViewModel is an object which is associated 541 00:25:39,070 --> 00:25:41,440 with a fragment or an activity, but is retained 542 00:25:41,440 --> 00:25:43,750 during configuration changes. 543 00:25:43,750 --> 00:25:48,190 So its scope is a kind of a logical scope of your activity. 544 00:25:48,190 --> 00:25:51,300 So what does this mean? 545 00:25:51,300 --> 00:25:51,900 Let's see. 546 00:25:51,900 --> 00:25:54,220 If we have access time and the current moment, and we 547 00:25:54,220 --> 00:25:55,540 can predict the future. 548 00:25:55,540 --> 00:25:57,670 And we know that activity is going to be created, 549 00:25:57,670 --> 00:25:59,390 and this means that all construction 550 00:25:59,390 --> 00:26:01,690 events are going to happen. 551 00:26:01,690 --> 00:26:05,440 During onCreate we will request ViewModel for the first time. 552 00:26:05,440 --> 00:26:07,780 We will create it, and after that this activity 553 00:26:07,780 --> 00:26:10,850 just uses this ViewModel. 554 00:26:10,850 --> 00:26:12,220 Very simple. 555 00:26:12,220 --> 00:26:16,060 Now we predict that the activity is going to be rotated. 556 00:26:16,060 --> 00:26:20,700 Let's see what's going to happen with our ViewModel. 557 00:26:20,700 --> 00:26:27,400 We will receive events, onPause, onStop, and onDestroy. 558 00:26:27,400 --> 00:26:30,880 But when all the segments are cured 559 00:26:30,880 --> 00:26:34,090 and your activity is destroyed, it's thrown away 560 00:26:34,090 --> 00:26:38,210 and is garbage collected, ViewModel survived it. 561 00:26:38,210 --> 00:26:42,070 And the new activity, which was created in place the old one 562 00:26:42,070 --> 00:26:44,510 uses the same, old object. 563 00:26:44,510 --> 00:26:48,520 So you can easily cache there LiveData as we want to 564 00:26:48,520 --> 00:26:50,690 or something else. 565 00:26:50,690 --> 00:26:52,720 The last case, what is going to happen 566 00:26:52,720 --> 00:26:55,600 if you have finished goal? 567 00:26:55,600 --> 00:26:58,280 Once again, we will receive these destruction events, 568 00:26:58,280 --> 00:27:01,570 but this time, ViewModel is available 569 00:27:01,570 --> 00:27:03,130 until onDestroy method. 570 00:27:03,130 --> 00:27:08,340 During onDestroy method, we will call onClear on this. 571 00:27:08,340 --> 00:27:11,860 Which notifies you if you have any currently running actions 572 00:27:11,860 --> 00:27:15,610 or any resources its time to close. 573 00:27:15,610 --> 00:27:18,900 And after that, it's going to be destroyed 574 00:27:18,900 --> 00:27:20,150 and garbage collected as well. 575 00:27:20,150 --> 00:27:24,310 So at the point when your activity is destroyed, 576 00:27:24,310 --> 00:27:27,340 it's not going to be recreated it again. 577 00:27:27,340 --> 00:27:30,980 Your ViewModel is gone as well. 578 00:27:30,980 --> 00:27:37,970 So let's quickly make our sample in ViewModel. 579 00:27:37,970 --> 00:27:40,900 So it starts with instantiating-- with creation 580 00:27:40,900 --> 00:27:43,270 of ViewModel class. 581 00:27:43,270 --> 00:27:47,860 We want to cache for user data to create a fill for that. 582 00:27:47,860 --> 00:27:50,680 We agree our activity needs to access this LiveData, 583 00:27:50,680 --> 00:27:52,450 so we create a getter for this. 584 00:27:52,450 --> 00:27:55,960 And finally, getter is extremely straightforward. 585 00:27:55,960 --> 00:27:59,530 If we already requested the data, we just return it. 586 00:27:59,530 --> 00:28:04,780 If the data is now, we'll request it from a web service 587 00:28:04,780 --> 00:28:06,580 and return it. 588 00:28:06,580 --> 00:28:07,422 Fine. 589 00:28:07,422 --> 00:28:08,880 We had [INAUDIBLE] on our activity. 590 00:28:08,880 --> 00:28:12,580 Now we need to get this LiveData from ViewModel. 591 00:28:12,580 --> 00:28:18,370 To get it, we need to create to get ViewModel somehow. 592 00:28:18,370 --> 00:28:19,450 So this is how we do it. 593 00:28:19,450 --> 00:28:21,970 Let's take a precise look at it. 594 00:28:21,970 --> 00:28:25,000 First of all, we need to get ViewModel provider object. 595 00:28:25,000 --> 00:28:27,250 This is an object which is associated 596 00:28:27,250 --> 00:28:28,570 with a fragment or an activity. 597 00:28:28,570 --> 00:28:34,270 It knows how to get already existing ViewModel from it 598 00:28:34,270 --> 00:28:36,740 or how to create a new one. 599 00:28:36,740 --> 00:28:39,250 If there is no existing ViewModel. 600 00:28:39,250 --> 00:28:44,650 After that, we request our myActivity ViewModel, 601 00:28:44,650 --> 00:28:48,617 and later everything is quite simple. 602 00:28:48,617 --> 00:28:49,450 We get the userData. 603 00:28:49,450 --> 00:28:54,730 We observe it to update the UI. 604 00:28:54,730 --> 00:28:59,860 So what are the rules of usage of ViewModel? 605 00:28:59,860 --> 00:29:04,660 So ViewModel manages the data for the UI. 606 00:29:04,660 --> 00:29:08,290 It means that it speaks with business 607 00:29:08,290 --> 00:29:11,510 parts of your application to retrieve the data. 608 00:29:11,510 --> 00:29:15,470 So it may be a repository pattern or any other pattern 609 00:29:15,470 --> 00:29:17,890 that they use. 610 00:29:17,890 --> 00:29:22,450 It also, it's for its user modifications 611 00:29:22,450 --> 00:29:24,140 back to these components. 612 00:29:24,140 --> 00:29:26,720 And now a good case for ViewModel 613 00:29:26,720 --> 00:29:30,730 is acting as a communication layer between fragments 614 00:29:30,730 --> 00:29:32,530 in one activity. 615 00:29:32,530 --> 00:29:36,490 And Yigit will speak about this later. 616 00:29:36,490 --> 00:29:40,840 But prior to this, things that you must not 617 00:29:40,840 --> 00:29:42,560 do in your ViewModel. 618 00:29:42,560 --> 00:29:46,580 So first of all, you must not access 619 00:29:46,580 --> 00:29:51,870 views and any other UI- related entities. 620 00:29:51,870 --> 00:29:54,670 The reason for that, they are going 621 00:29:54,670 --> 00:29:57,010 to be created during configuration change. 622 00:29:57,010 --> 00:30:02,400 If you try to use them, you will ever use stale data from there, 623 00:30:02,400 --> 00:30:05,250 ever to leak them. 624 00:30:05,250 --> 00:30:09,230 That's going to finish bad. 625 00:30:09,230 --> 00:30:12,280 And it's fragmented or activity's job 626 00:30:12,280 --> 00:30:17,110 to bind the data which you will get from a ViewModel 627 00:30:17,110 --> 00:30:21,260 with actual UI, text use, buttons. 628 00:30:21,260 --> 00:30:23,190 I don't know what else. 629 00:30:23,190 --> 00:30:26,590 And one more thing, there are sources 630 00:30:26,590 --> 00:30:31,120 which sound more harmless like strings or drawable, 631 00:30:31,120 --> 00:30:33,790 and you may think, I may cash it here. 632 00:30:33,790 --> 00:30:38,020 No, they depend on current configuration state of state 633 00:30:38,020 --> 00:30:38,800 as well. 634 00:30:38,800 --> 00:30:43,360 So yes, right now you may have just one resource 635 00:30:43,360 --> 00:30:46,540 for every configuration, but later, you 636 00:30:46,540 --> 00:30:49,870 will add in the same resource for a different configuration. 637 00:30:49,870 --> 00:30:54,010 You will easily forget to update your ViewModel. 638 00:30:54,010 --> 00:30:58,540 And you may not notice this, but your users 639 00:30:58,540 --> 00:31:00,250 will see the invalid UI. 640 00:31:00,250 --> 00:31:02,230 And this is just ugly. 641 00:31:02,230 --> 00:31:06,970 And now Yigit will speak about Inter Fragment communications. 642 00:31:06,970 --> 00:31:10,510 643 00:31:10,510 --> 00:31:12,270 YIGIT BOYAR: So I want to talk about one 644 00:31:12,270 --> 00:31:16,050 of my favorite features about ViewModel, 645 00:31:16,050 --> 00:31:19,020 which is communicating between multiple fragments 646 00:31:19,020 --> 00:31:21,980 of the same activity. 647 00:31:21,980 --> 00:31:25,200 It's good that UI like this, like the Gmail on the tablet 648 00:31:25,200 --> 00:31:29,500 where on the left side you pick an email and on the right side, 649 00:31:29,500 --> 00:31:31,860 it shows the contents of the email. 650 00:31:31,860 --> 00:31:34,560 Now usually you will implement this as a fragment 651 00:31:34,560 --> 00:31:37,940 on the left which picks something from the list, 652 00:31:37,940 --> 00:31:39,780 and another fragment on the right, which 653 00:31:39,780 --> 00:31:42,960 shows how to show the contents of an email 654 00:31:42,960 --> 00:31:45,330 so that if you're on the phone you can reuse the same 655 00:31:45,330 --> 00:31:48,150 fragments but separate from each other. 656 00:31:48,150 --> 00:31:52,170 Now if you ever tried to write a UI like this, if you ever 657 00:31:52,170 --> 00:31:55,105 tried to make these two fragments talk to each other, 658 00:31:55,105 --> 00:31:56,220 it's a pain in the neck. 659 00:31:56,220 --> 00:31:57,240 It's very, very hard. 660 00:31:57,240 --> 00:31:59,510 Like you need to create an interface. 661 00:31:59,510 --> 00:32:01,530 But then what if one fragment gets 662 00:32:01,530 --> 00:32:03,540 created before the other one. 663 00:32:03,540 --> 00:32:05,940 An activity needs to talk to each other. 664 00:32:05,940 --> 00:32:07,931 Or like when the activities are restored, 665 00:32:07,931 --> 00:32:09,430 you don't really know which fragment 666 00:32:09,430 --> 00:32:11,340 will be restored first. 667 00:32:11,340 --> 00:32:14,880 It is really hard to manage this state. 668 00:32:14,880 --> 00:32:21,020 But we can actually solve this very elegantly using ViewModel. 669 00:32:21,020 --> 00:32:23,930 So let's say so these two families actually want 670 00:32:23,930 --> 00:32:26,390 to talk about a selected email. 671 00:32:26,390 --> 00:32:29,060 This is the information they want to share. 672 00:32:29,060 --> 00:32:30,950 So let's put it inside a ViewModel 673 00:32:30,950 --> 00:32:33,920 and we are going to call this shared ViewModel. 674 00:32:33,920 --> 00:32:36,130 So it has a mutable LiveData inside it 675 00:32:36,130 --> 00:32:41,430 which you call selected, and it provides two very simple APIs. 676 00:32:41,430 --> 00:32:45,410 The first one says, set the select email to this email. 677 00:32:45,410 --> 00:32:49,610 Another one says, get the selected email as a LiveData. 678 00:32:49,610 --> 00:32:52,510 It's a really simple ViewModel. 679 00:32:52,510 --> 00:32:56,030 But now once we have this, let's go back to our fragments 680 00:32:56,030 --> 00:32:58,260 and see how we can use this. 681 00:32:58,260 --> 00:33:00,920 So inside the content fragment, which is the one 682 00:33:00,920 --> 00:33:03,650 that wants to display the contents of the email. 683 00:33:03,650 --> 00:33:07,550 It wants to know when the selected email changes. 684 00:33:07,550 --> 00:33:09,930 So we're going to go-- so we have already seen this. 685 00:33:09,930 --> 00:33:12,470 You can go to ViewModel providers class 686 00:33:12,470 --> 00:33:15,230 and get the ViewModel providers of this fragment. 687 00:33:15,230 --> 00:33:19,170 But we actually want ViewModel not from this fragment, 688 00:33:19,170 --> 00:33:21,330 we want it from our activity. 689 00:33:21,330 --> 00:33:25,480 So all you have to do tell it to do it from your activity. 690 00:33:25,480 --> 00:33:28,520 Now it's going to return your ViewModel in the activity 691 00:33:28,520 --> 00:33:33,140 scope, and I will say, get for the shared ViewModel. 692 00:33:33,140 --> 00:33:35,770 Now, the very first time one of the fragments called this, 693 00:33:35,770 --> 00:33:37,460 we are going to create a new one. 694 00:33:37,460 --> 00:33:39,520 When the other fragment comes alive, 695 00:33:39,520 --> 00:33:42,830 it's going to receive the same ViewModel instance. 696 00:33:42,830 --> 00:33:44,100 And I will do the same thing. 697 00:33:44,100 --> 00:33:46,650 So this one says, get the selected email. 698 00:33:46,650 --> 00:33:48,662 Start observing on it. 699 00:33:48,662 --> 00:33:50,540 Really similarly, in the select fragment 700 00:33:50,540 --> 00:33:54,500 which was the one on the left by user pics and email, 701 00:33:54,500 --> 00:33:57,410 we get the same ViewModel. 702 00:33:57,410 --> 00:34:00,680 And whenever the user selects an email from the list, 703 00:34:00,680 --> 00:34:03,080 we just call the ViewModel- related method 704 00:34:03,080 --> 00:34:05,120 to change the selected email. 705 00:34:05,120 --> 00:34:08,239 Now these two fragments talking to each other 706 00:34:08,239 --> 00:34:10,710 without actually talking to each other. 707 00:34:10,710 --> 00:34:13,730 How does this really happen? 708 00:34:13,730 --> 00:34:15,380 So if we go back to our UI. 709 00:34:15,380 --> 00:34:18,679 So we have the selector on the left, the content on the right. 710 00:34:18,679 --> 00:34:21,320 But if you look at the details, actually both of these 711 00:34:21,320 --> 00:34:23,060 are talking to a shared ViewModel. 712 00:34:23,060 --> 00:34:25,040 They never talk to each other. 713 00:34:25,040 --> 00:34:28,580 The video of this solution is that if you're on the phone, 714 00:34:28,580 --> 00:34:31,280 let's say one fragment replaces the other one, 715 00:34:31,280 --> 00:34:33,080 there's no room for error. 716 00:34:33,080 --> 00:34:35,270 Like the fragment still talks to a ViewModel. 717 00:34:35,270 --> 00:34:37,370 ViewModels always that nothing will crash. 718 00:34:37,370 --> 00:34:39,770 They don't even care the other one is there. 719 00:34:39,770 --> 00:34:42,810 720 00:34:42,810 --> 00:34:45,349 Okay, so this is a lot of information, 721 00:34:45,349 --> 00:34:47,670 and there's further details about how 722 00:34:47,670 --> 00:34:49,170 these life cycles work. 723 00:34:49,170 --> 00:34:51,330 We really spent a lot of time to make 724 00:34:51,330 --> 00:34:55,260 these handle most common used cases on Android. 725 00:34:55,260 --> 00:34:58,620 So we come in just the first trade out. 726 00:34:58,620 --> 00:35:03,150 You could try it now, in [INAUDIBLE]. 727 00:35:03,150 --> 00:35:05,850 Please check out all of the architecture components. 728 00:35:05,850 --> 00:35:08,640 These are things that actually work very well together. 729 00:35:08,640 --> 00:35:11,070 We have an architecture guide which shows you 730 00:35:11,070 --> 00:35:15,330 how to use these things together to write a good application. 731 00:35:15,330 --> 00:35:16,980 And also check our code labs. 732 00:35:16,980 --> 00:35:20,490 We have code lab sections that will give you a first glimpse 733 00:35:20,490 --> 00:35:23,841 of how LifeCycles work. 734 00:35:23,841 --> 00:35:24,340 Thank you 735 00:35:24,340 --> 00:35:26,815 [APPLAUSE] 736 00:35:26,815 --> 00:35:29,055 [MUSIC PLAYING] 737 00:35:29,055 --> 00:00:00,000 |
09 09 2017