1 00:00:03,890 --> 00:00:05,759 Alright so we're going to talk about 2 00:00:05,759 --> 00:00:08,250 singleton classes, and specifically the 3 00:00:08,250 --> 00:00:10,980 AppDatabase class. So our AppDatabase 4 00:00:10,980 --> 00:00:13,019 class should work and we'll be able to 5 00:00:13,019 --> 00:00:15,660 test it soon. Before that though there's 6 00:00:15,660 --> 00:00:17,760 a change I want to make - I want to make 7 00:00:17,760 --> 00:00:20,970 it a singleton. Now a singleton class is 8 00:00:20,970 --> 00:00:23,310 one that only allows a single instance 9 00:00:23,310 --> 00:00:26,369 to be created. We've used a few singletons 10 00:00:26,369 --> 00:00:28,830 so far - the most recent is the Content 11 00:00:28,830 --> 00:00:31,289 Resolver. There's only a single Content 12 00:00:31,289 --> 00:00:33,270 Resolver instance, although it's hard to 13 00:00:33,270 --> 00:00:35,489 check that from the source code because 14 00:00:35,489 --> 00:00:37,050 Content Resolver's an abstract class, 15 00:00:37,050 --> 00:00:39,480 and the implementation's provided by 16 00:00:39,480 --> 00:00:42,210 Android. Now we also created a singleton - 17 00:00:42,210 --> 00:00:45,899 our Tasks Contract object. In Kotlin, 18 00:00:45,899 --> 00:00:48,300 object is automatically a thread 19 00:00:48,300 --> 00:00:51,149 safe singleton. Unfortunately though, we 20 00:00:51,149 --> 00:00:52,860 can't make our AppDatabase class an 21 00:00:52,860 --> 00:00:55,379 object, and that's because we can't pass 22 00:00:55,379 --> 00:00:58,109 arguments to an object constructor. The 23 00:00:58,109 --> 00:00:59,789 reason for that is because objects don't 24 00:00:59,789 --> 00:01:02,309 actually have a constructor. We can use 25 00:01:02,309 --> 00:01:04,860 an object in our class to return a 26 00:01:04,860 --> 00:01:07,500 single instance of it. There's two stages 27 00:01:07,500 --> 00:01:10,439 to making a class into a singleton. The 28 00:01:10,439 --> 00:01:13,170 first step's easy - we mark the constructor 29 00:01:13,170 --> 00:01:15,570 as private so that nothing else can 30 00:01:15,570 --> 00:01:18,299 instantiate our class. So let's go ahead 31 00:01:18,299 --> 00:01:22,020 and do that now. So we've got - up here 32 00:01:22,020 --> 00:01:24,180 in our definition - internal class App 33 00:01:24,180 --> 00:01:26,580 Database constructor. We're going to put 34 00:01:26,580 --> 00:01:29,180 the private key word before constructor, 35 00:01:29,180 --> 00:01:32,490 so we're now marking that as private. So 36 00:01:32,490 --> 00:01:34,229 now the only thing that can create an 37 00:01:34,229 --> 00:01:36,450 instance of AppDatabase is AppData 38 00:01:36,450 --> 00:01:39,299 base itself, either via its own functions, 39 00:01:39,299 --> 00:01:41,880 or functions in an inner class or 40 00:01:41,880 --> 00:01:44,670 companion object. Now the reason I've 41 00:01:44,670 --> 00:01:46,860 done that is because we only want a 42 00:01:46,860 --> 00:01:48,869 single instance of this class to exist. 43 00:01:48,869 --> 00:01:51,750 As well as creating our database, this 44 00:01:51,750 --> 00:01:54,000 class also provides the connection to 45 00:01:54,000 --> 00:01:55,200 the database. 46 00:01:55,200 --> 00:01:57,659 Sqlite can support multiple users 47 00:01:57,659 --> 00:02:00,180 but it locks the entire database when 48 00:02:00,180 --> 00:02:02,670 writing to it. Our app is a single user, 49 00:02:02,670 --> 00:02:04,979 but if we allowed many instances of this 50 00:02:04,979 --> 00:02:07,890 AppDatabase class to be created, then 51 00:02:07,890 --> 00:02:09,899 each one would, effectively, be a 52 00:02:09,899 --> 00:02:12,330 different sqlite user, with its own 53 00:02:12,330 --> 00:02:13,230 connection to the 54 00:02:13,230 --> 00:02:15,390 database. Now that's not the end of the 55 00:02:15,390 --> 00:02:17,370 world, and the app would probably 56 00:02:17,370 --> 00:02:19,650 function just fine most of the time, as 57 00:02:19,650 --> 00:02:22,500 long as several instances didn't all try 58 00:02:22,500 --> 00:02:24,720 to execute the code to create the 59 00:02:24,720 --> 00:02:27,440 database tables simultaneously, of course. 60 00:02:27,440 --> 00:02:30,180 Now obviously, if you allow instances 61 00:02:30,180 --> 00:02:32,640 of a class to be created at will, then 62 00:02:32,640 --> 00:02:34,349 there's no way to guarantee that there's 63 00:02:34,349 --> 00:02:36,720 only one instance. So making the 64 00:02:36,720 --> 00:02:39,120 constructor private is the first step in 65 00:02:39,120 --> 00:02:42,450 creating a singleton class. Now equally, 66 00:02:42,450 --> 00:02:44,940 obviously, if there's no way to create 67 00:02:44,940 --> 00:02:47,160 any instances of a class, then it's not going 68 00:02:47,160 --> 00:02:49,440 to be much use to anyone unless all its 69 00:02:49,440 --> 00:02:51,720 fields and methods are available without 70 00:02:51,720 --> 00:02:53,910 creating an instance, as we saw with our 71 00:02:53,910 --> 00:02:57,599 columns object in the Tasks Contract. So 72 00:02:57,599 --> 00:02:59,220 how do we allow that single instance to 73 00:02:59,220 --> 00:03:01,799 be created. Well you'll find many 74 00:03:01,799 --> 00:03:03,810 examples of how to create Singleton's on 75 00:03:03,810 --> 00:03:06,709 the internet. They're mainly in Java, and 76 00:03:06,709 --> 00:03:09,290 unfortunately many of them are flawed. 77 00:03:09,290 --> 00:03:12,480 Android is a multi-threaded framework 78 00:03:12,480 --> 00:03:15,299 and class instances can be created on 79 00:03:15,299 --> 00:03:18,299 more than one thread. Any attempt to 80 00:03:18,299 --> 00:03:20,849 implement a singleton, has to cater for 81 00:03:20,849 --> 00:03:23,250 the same objects being created at the 82 00:03:23,250 --> 00:03:26,819 same time, from different threads. In Java, 83 00:03:26,819 --> 00:03:29,160 one solution is to use a static inner 84 00:03:29,160 --> 00:03:31,530 class which has a method returning an 85 00:03:31,530 --> 00:03:34,049 instance of the singleton class. Now the 86 00:03:34,049 --> 00:03:36,060 obvious solution of checking if the 87 00:03:36,060 --> 00:03:38,099 instance is null, than creating a new 88 00:03:38,099 --> 00:03:40,560 instance only if it is, doesn't work if 89 00:03:40,560 --> 00:03:43,079 another thread calls the method before 90 00:03:43,079 --> 00:03:46,230 the first call has created the object. So 91 00:03:46,230 --> 00:03:47,819 that method has to cope with being 92 00:03:47,819 --> 00:03:50,040 called from multiple threads at the same 93 00:03:50,040 --> 00:03:53,040 time, and a common solution is the double 94 00:03:53,040 --> 00:03:55,590 checked locking algorithm. So that 95 00:03:55,590 --> 00:03:57,720 basically does a null check twice, and 96 00:03:57,720 --> 00:04:00,720 locks the instance variable after the 97 00:04:00,720 --> 00:04:03,269 first check. Now there's a bit more to it 98 00:04:03,269 --> 00:04:05,329 than that, and as I've mentioned, 99 00:04:05,329 --> 00:04:07,739 multi-threaded programming is extremely 100 00:04:07,739 --> 00:04:10,440 difficult to get right. So let's have a 101 00:04:10,440 --> 00:04:12,629 look at how we might implement that in a 102 00:04:12,629 --> 00:04:14,790 companion object, and then I'll show you 103 00:04:14,790 --> 00:04:18,060 our reusable solution. So our companion 104 00:04:18,060 --> 00:04:20,130 object will have a getInstance function, 105 00:04:20,130 --> 00:04:23,430 to return an instance of AppDatabase. So 106 00:04:23,430 --> 00:04:24,570 I'm going to go ahead and add this at 107 00:04:24,570 --> 00:04:27,320 the end of the class. 108 00:04:27,320 --> 00:04:29,280 Alright so I'm going to come down here, 109 00:04:29,280 --> 00:04:30,600 right at the bottom of the class 110 00:04:30,600 --> 00:04:33,660 before the last right curly brace. We're 111 00:04:33,660 --> 00:04:36,000 going to type companion object and press 112 00:04:36,000 --> 00:04:38,220 ENTER there, and you can see that Android 113 00:04:38,220 --> 00:04:40,440 studio fills out the rest for us. Then 114 00:04:40,440 --> 00:04:46,220 I'm going to type private var instance 115 00:04:46,220 --> 00:04:50,840 colon AppDatabase question mark equals null. 116 00:04:50,840 --> 00:04:53,550 Then also what I'm going to do, is add 117 00:04:53,550 --> 00:04:58,620 the volatile annotation to that 118 00:04:58,620 --> 00:05:01,349 definition there, and then I'm going to create 119 00:05:01,349 --> 00:05:03,900 a function called getInstance, fun get 120 00:05:03,900 --> 00:05:07,410 Instance, and parentheses. We're going to 121 00:05:07,410 --> 00:05:12,360 pass a context, so context : Context, then 122 00:05:12,360 --> 00:05:14,729 outside of the parentheses : App 123 00:05:14,729 --> 00:05:18,449 Database is equal to. Then on the next line 124 00:05:18,449 --> 00:05:22,130 we're going to type instance question mark : 125 00:05:22,130 --> 00:05:27,030 synchronized, in a parentheses, this. Then 126 00:05:27,030 --> 00:05:29,250 left and right curly braces, and then 127 00:05:29,250 --> 00:05:30,479 we're going to type within that curly 128 00:05:30,479 --> 00:05:32,539 brace, within those curly braces, instance 129 00:05:32,539 --> 00:05:37,440 question mark : AppDatabase. Then in 130 00:05:37,440 --> 00:05:42,949 parentheses it's going to be context, and 131 00:05:42,949 --> 00:05:45,030 then outside of the right parentheses, 132 00:05:45,030 --> 00:05:47,580 dot also, and then we're going to 133 00:05:47,580 --> 00:05:49,080 introduce left and right curly braces 134 00:05:49,080 --> 00:05:53,750 again and type instance equals it. 135 00:05:53,750 --> 00:05:56,220 Alright, so what have we done here? Well 136 00:05:56,220 --> 00:05:59,009 we've used two Elvis operators which are 137 00:05:59,009 --> 00:06:02,550 our to two null checks. On the first line, we 138 00:06:02,550 --> 00:06:04,110 return instance if it isn't null, 139 00:06:04,110 --> 00:06:06,659 otherwise the synchronized block of code 140 00:06:06,659 --> 00:06:09,630 is executed. So that locks the variable 141 00:06:09,630 --> 00:06:11,729 to prevent access from another thread. 142 00:06:11,729 --> 00:06:14,130 Inside that block we once again return 143 00:06:14,130 --> 00:06:17,400 instance, if it now isn't null, so if 144 00:06:17,400 --> 00:06:19,169 another thread has managed to create it, 145 00:06:19,169 --> 00:06:22,380 in other words. But if it is null, we create 146 00:06:22,380 --> 00:06:24,720 a new AppDatabase instance and then 147 00:06:24,720 --> 00:06:28,380 return that. Now the also function calls 148 00:06:28,380 --> 00:06:30,810 the specified block, a simple assignment 149 00:06:30,810 --> 00:06:33,539 here, and returns it. We assign the new 150 00:06:33,539 --> 00:06:35,909 instance, represented by it, to our 151 00:06:35,909 --> 00:06:38,159 instance variable. Now whenever this 152 00:06:38,159 --> 00:06:39,870 function's called again, 153 00:06:39,870 --> 00:06:41,790 instance won't be null and will be 154 00:06:41,790 --> 00:06:44,460 immediately returned. Now don't worry too 155 00:06:44,460 --> 00:06:46,140 much about exactly how this code's 156 00:06:46,140 --> 00:06:48,440 working. As I've said a few times, 157 00:06:48,440 --> 00:06:50,610 multi-threaded programming is very 158 00:06:50,610 --> 00:06:52,740 difficult. Fortunately though, Android 159 00:06:52,740 --> 00:06:54,840 gives us things like async tasks and 160 00:06:54,840 --> 00:06:57,750 loaders to take care of a lot of 161 00:06:57,750 --> 00:06:59,970 the complexity. Most of the time it's not 162 00:06:59,970 --> 00:07:02,010 something we need to worry about. I mean 163 00:07:02,010 --> 00:07:03,090 do you really want to worry about 164 00:07:03,090 --> 00:07:05,040 synchronizing threads and using the 165 00:07:05,040 --> 00:07:07,350 volatile annotation? You can click to 166 00:07:07,350 --> 00:07:09,330 get a description of why that volatile 167 00:07:09,330 --> 00:07:11,490 annotation's there. It makes changes to 168 00:07:11,490 --> 00:07:13,920 instance immediately available to other 169 00:07:13,920 --> 00:07:15,840 threads, and is one of the many things that 170 00:07:15,840 --> 00:07:18,510 people get wrong. OK, so that code as 171 00:07:18,510 --> 00:07:21,090 we've written it will work, but frankly 172 00:07:21,090 --> 00:07:23,490 it's horrible. Having to modify it to 173 00:07:23,490 --> 00:07:26,250 create different singleton classes could 174 00:07:26,250 --> 00:07:28,470 be a good way to introduce bugs. What 175 00:07:28,470 --> 00:07:30,780 would be really useful is some class 176 00:07:30,780 --> 00:07:32,700 that we could use to do this all for us. 177 00:07:32,700 --> 00:07:35,160 Now the good news here is that such a 178 00:07:35,160 --> 00:07:38,250 class exists. There's a link to the 179 00:07:38,250 --> 00:07:40,440 article about it in the resources 180 00:07:40,440 --> 00:07:42,120 section for this video, and actually 181 00:07:42,120 --> 00:07:43,020 you'll see that in a moment. 182 00:07:43,020 --> 00:07:44,910 I'm not going to open the link in my 183 00:07:44,910 --> 00:07:46,950 browser though, and that's because the 184 00:07:46,950 --> 00:07:49,230 article isn't licensed for our 185 00:07:49,230 --> 00:07:51,300 commercial use so I can't really go 186 00:07:51,300 --> 00:07:53,370 through it all in this video. Now the 187 00:07:53,370 --> 00:07:54,600 article may not be available for 188 00:07:54,600 --> 00:07:56,190 commercial use, but we've had 189 00:07:56,190 --> 00:07:58,920 confirmation from Christophe Beyls, the 190 00:07:58,920 --> 00:08:02,040 author, that the code is. Now if you 191 00:08:02,040 --> 00:08:04,020 want to use his singleton class in your 192 00:08:04,020 --> 00:08:06,720 own code, that's fine. So what I'm going 193 00:08:06,720 --> 00:08:09,030 to do now is create a new Kotlin file 194 00:08:09,030 --> 00:08:14,130 class. I'll go ahead and do that, and I'm 195 00:08:14,130 --> 00:08:18,920 going to call this one SingletonHolder, 196 00:08:18,920 --> 00:08:22,140 and what I'm then going to do is paste 197 00:08:22,140 --> 00:08:25,170 in the code. And what I'm going to do is 198 00:08:25,170 --> 00:08:27,210 make sure that I delete these default 199 00:08:27,210 --> 00:08:29,070 comments, because I'm certainly not 200 00:08:29,070 --> 00:08:31,110 trying to claim any credit for this 201 00:08:31,110 --> 00:08:33,510 code. So I'm going to paste that in there now, and 202 00:08:33,510 --> 00:08:35,549 this is the code there from Christophe 203 00:08:35,549 --> 00:08:37,650 Beyls, as I said. So as you can see 204 00:08:37,650 --> 00:08:39,270 though, I have added a KDoc to show who 205 00:08:39,270 --> 00:08:41,940 wrote the code, and also the URL for the 206 00:08:41,940 --> 00:08:43,650 article. Have a read through the article, 207 00:08:43,650 --> 00:08:45,450 especially if you want to learn a bit 208 00:08:45,450 --> 00:08:48,960 more about how all this works. So the 209 00:08:48,960 --> 00:08:51,090 only change that I've made to Christophe's 210 00:08:51,090 --> 00:08:54,090 code is to add the usual logging, our 211 00:08:54,090 --> 00:08:56,160 usual logging. There's only, and that's 212 00:08:56,160 --> 00:08:57,600 only there really to make it easier to 213 00:08:57,600 --> 00:08:59,730 understand what happens when we run the 214 00:08:59,730 --> 00:09:01,590 app, and you'll probably want to delete 215 00:09:01,590 --> 00:09:03,930 the constant logging line if you use 216 00:09:03,930 --> 00:09:06,420 this class in your own apps. So this 217 00:09:06,420 --> 00:09:09,180 class is basically a generic 218 00:09:09,180 --> 00:09:11,610 version of the code I've just added to 219 00:09:11,610 --> 00:09:14,040 our AppDatabase class in the companion 220 00:09:14,040 --> 00:09:16,590 object. Alright. So what I'm going to do 221 00:09:16,590 --> 00:09:18,510 is go back to that code and comment out 222 00:09:18,510 --> 00:09:27,240 my companion object, and what we're going 223 00:09:27,240 --> 00:09:28,770 to do is use the singleton class 224 00:09:28,770 --> 00:09:31,170 instead. So what I'm going to do is, above 225 00:09:31,170 --> 00:09:32,910 that commented out code, I'm going to 226 00:09:32,910 --> 00:09:35,610 type companion object. Then what I'm 227 00:09:35,610 --> 00:09:38,490 going to do is delete the left and right 228 00:09:38,490 --> 00:09:40,020 clearly braces - we don't need them - and 229 00:09:40,020 --> 00:09:42,660 instead I'm going to put colon. I'm going to type 230 00:09:42,660 --> 00:09:46,440 singleton holder, then in a less than and 231 00:09:46,440 --> 00:09:47,580 greater than sign there I'm going to type 232 00:09:47,580 --> 00:09:53,250 AppDatabase comma context, and then I'm 233 00:09:53,250 --> 00:09:56,190 going to type parentheses two colons and 234 00:09:56,190 --> 00:10:00,600 AppDatabase. Now that's a lot easier. You 235 00:10:00,600 --> 00:10:02,760 can use it in any class - it has a 236 00:10:02,760 --> 00:10:05,130 single argument constructor just by 237 00:10:05,130 --> 00:10:07,590 changing the two occurrences of the 238 00:10:07,590 --> 00:10:09,930 class name. Now passing just one argument 239 00:10:09,930 --> 00:10:11,370 to the constructor is normally all 240 00:10:11,370 --> 00:10:13,260 you'll need. You'll often need to pass just 241 00:10:13,260 --> 00:10:15,680 a single argument, a context for example, 242 00:10:15,680 --> 00:10:18,420 to your singletons. Now I said 243 00:10:18,420 --> 00:10:20,700 that's normally all you'll need, but I don't 244 00:10:20,700 --> 00:10:21,810 want to imply that creating 245 00:10:21,810 --> 00:10:24,030 singletons is normal. They're not 246 00:10:24,030 --> 00:10:25,860 something you need to create very often, 247 00:10:25,860 --> 00:10:28,500 but when you do need to create them, you 248 00:10:28,500 --> 00:10:31,320 now have a way to do it right. Whenever 249 00:10:31,320 --> 00:10:32,940 another class needs an instance of this 250 00:10:32,940 --> 00:10:35,310 AppDatabase class, it calls the get 251 00:10:35,310 --> 00:10:37,350 Instance method. The first time that's 252 00:10:37,350 --> 00:10:37,800 called, 253 00:10:37,800 --> 00:10:40,260 instance will be null and a new instance 254 00:10:40,260 --> 00:10:41,820 of the AppDatabase class will be 255 00:10:41,820 --> 00:10:44,310 created. And every time it's called after 256 00:10:44,310 --> 00:10:46,440 that, the caller will get a reference to 257 00:10:46,440 --> 00:10:48,450 the single instance of the class that's 258 00:10:48,450 --> 00:10:50,940 stored in the instance field. Alright. 259 00:10:50,940 --> 00:10:52,890 So in the next video we're going to add 260 00:10:52,890 --> 00:10:55,140 some code to the onUpgrade function, and 261 00:10:55,140 --> 00:10:57,690 then run a very basic test of the App 262 00:10:57,690 --> 00:11:01,910 Database class. See you in the next video.