1
00:00:00,000 --> 00:00:02,463
(futuristic electronic music)

2
00:00:02,463 --> 00:00:05,010
(keyboard keys clack)

3
00:00:05,010 --> 00:00:05,843
So at this point now,

4
00:00:05,843 --> 00:00:08,440
there's only a few more changes we need to make to the app

5
00:00:08,440 --> 00:00:11,040
now that we've moved the non-UI functionality

6
00:00:11,040 --> 00:00:12,680
out of MainActivity.

7
00:00:12,680 --> 00:00:13,870
The first thing I want to do, though,

8
00:00:13,870 --> 00:00:16,530
isn't directly related to this change.

9
00:00:16,530 --> 00:00:18,920
I recorded the original top10downloader videos

10
00:00:18,920 --> 00:00:21,710
before Kotlin allowed top level constants.

11
00:00:21,710 --> 00:00:23,860
We have covered that now in an earlier video,

12
00:00:23,860 --> 00:00:25,090
and I've been using them ever since,

13
00:00:25,090 --> 00:00:27,240
so I'm gonna start by moving our constants

14
00:00:27,240 --> 00:00:28,680
from our MainActivity class

15
00:00:29,920 --> 00:00:31,053
out of the Main class.

16
00:00:32,180 --> 00:00:33,790
Go up to the top there,

17
00:00:33,790 --> 00:00:35,890
and the ones we want to move here are TAG.

18
00:00:37,728 --> 00:00:39,340
We also have STATE and STATE_LIMIT,

19
00:00:39,340 --> 00:00:41,030
so I'm gonna start by moving TAG

20
00:00:42,660 --> 00:00:44,030
above the class definition,

21
00:00:44,030 --> 00:00:46,960
and also, for STATE_LIMIT and STATE_URL,

22
00:00:46,960 --> 00:00:48,830
we'll do the same thing there.

23
00:00:48,830 --> 00:00:50,620
Paste them up there.

24
00:00:50,620 --> 00:00:52,093
We'll also make them const,

25
00:00:58,830 --> 00:01:00,340
like so,

26
00:01:00,340 --> 00:01:02,110
and what I'll also do is take the opportunity

27
00:01:02,110 --> 00:01:06,070
to delete the toString function from the FeedEntry class.

28
00:01:06,070 --> 00:01:08,990
We used to, in a very early version of this app,

29
00:01:08,990 --> 00:01:11,010
before we created the proper layout for the dialer,

30
00:01:11,010 --> 00:01:12,460
so it's fairly redundant now.

31
00:01:14,398 --> 00:01:16,680
Plus, that cleans things up a little bit as well.

32
00:01:16,680 --> 00:01:18,150
All right, so on to what changes

33
00:01:18,150 --> 00:01:19,810
we need to make at this point.

34
00:01:19,810 --> 00:01:22,253
Well, firstly, looking at the onCreate function,

35
00:01:23,470 --> 00:01:25,670
it's attempting to download the data.

36
00:01:25,670 --> 00:01:27,270
So it should just now be subscribing

37
00:01:27,270 --> 00:01:30,140
to the ViewModel's LiveData instead,

38
00:01:30,140 --> 00:01:31,727
so I would probably start by creating

39
00:01:31,727 --> 00:01:34,630
our feedViewModel instance in onCreate.

40
00:01:34,630 --> 00:01:36,440
So I'm gonna do that for now.

41
00:01:36,440 --> 00:01:38,650
I will do that after this code

42
00:01:38,650 --> 00:01:41,250
for the savedInstanceState.

43
00:01:41,250 --> 00:01:42,083
So val

44
00:01:43,300 --> 00:01:44,133
feedViewModel

45
00:01:45,210 --> 00:01:46,220
equals

46
00:01:46,220 --> 00:01:47,740
as ViewModel,

47
00:01:47,740 --> 00:01:49,400
and notice, because we've added the entry in gradle,

48
00:01:49,400 --> 00:01:52,130
Providers is now an option we can select.

49
00:01:52,130 --> 00:01:54,840
So it's ViewModelProviders.of.

50
00:01:54,840 --> 00:01:57,727
It has this and then a right parentheses,

51
00:01:57,727 --> 00:01:58,640
.get.

52
00:01:58,640 --> 00:01:59,790
Then in parentheses again,

53
00:01:59,790 --> 00:02:04,363
FeedViewModel::class.java.

54
00:02:06,060 --> 00:02:06,900
Then on the next line,

55
00:02:06,900 --> 00:02:08,900
we're going to do a feedModel,

56
00:02:08,900 --> 00:02:10,477
or feedViewModel, I should say,

57
00:02:10,477 --> 00:02:14,400
.feedEntries.observe

58
00:02:14,400 --> 00:02:15,667
parentheses this,.

59
00:02:16,550 --> 00:02:17,930
On the next line,

60
00:02:17,930 --> 00:02:19,323
we're gonna type Observer,

61
00:02:20,510 --> 00:02:22,720
and the top there will be

62
00:02:22,720 --> 00:02:24,708
List of

63
00:02:24,708 --> 00:02:25,541
FeedEntry,

64
00:02:27,880 --> 00:02:29,600
and then we're gonna create a lambda function,

65
00:02:29,600 --> 00:02:32,143
so left and right curly braces,

66
00:02:33,080 --> 00:02:34,933
and it's gonna be feedEntries,

67
00:02:38,230 --> 00:02:40,063
then our arrow,

68
00:02:41,981 --> 00:02:42,898
feedAdapter

69
00:02:45,170 --> 00:02:47,243
.setFeedList,

70
00:02:48,170 --> 00:02:50,743
then in parentheses, feedEntries.

71
00:02:51,910 --> 00:02:53,230
Close your parentheses.

72
00:02:53,230 --> 00:02:54,930
Then we got our right curly brace

73
00:02:54,930 --> 00:02:56,480
and then a closing parentheses.

74
00:02:57,534 --> 00:02:59,500
Now, this is very similar to what we've done before.

75
00:02:59,500 --> 00:03:01,590
Instead of setting the text in a widget,

76
00:03:01,590 --> 00:03:03,810
we're setting the data in our Adapter.

77
00:03:03,810 --> 00:03:06,670
That was originally handled by the DownloadData class,

78
00:03:06,670 --> 00:03:08,950
but now it's the job of MainActivity.

79
00:03:08,950 --> 00:03:10,930
The Adapter populates the List View,

80
00:03:10,930 --> 00:03:12,700
which is part of the UI,

81
00:03:12,700 --> 00:03:13,670
and we got an error there,

82
00:03:13,670 --> 00:03:17,020
unsurprisingly because we haven't yet created the Adapter.

83
00:03:17,020 --> 00:03:18,310
So let's go ahead and do that.

84
00:03:18,310 --> 00:03:20,604
We'll add that just after the onCreate call

85
00:03:20,604 --> 00:03:21,540
before the check for,

86
00:03:21,540 --> 00:03:24,440
if savedInstanceState is not equal to null.

87
00:03:24,440 --> 00:03:26,058
So do a val,

88
00:03:26,058 --> 00:03:27,620
feedAdapter is equal to

89
00:03:28,533 --> 00:03:29,770
and FeedAdapter,

90
00:03:29,770 --> 00:03:31,713
and in parentheses, this,

91
00:03:32,578 --> 00:03:35,173
and it's gonna be R.layout.list_record,

92
00:03:37,620 --> 00:03:38,453
comma,

93
00:03:38,453 --> 00:03:40,027
then EMPTY_FEED_LIST.

94
00:03:41,896 --> 00:03:43,476
That creates the Adapter,

95
00:03:43,476 --> 00:03:46,893
and we're gonna do an xmlListView.adapter

96
00:03:47,730 --> 00:03:49,310
is equal to,

97
00:03:49,310 --> 00:03:51,480
our newly created feedAdapter.

98
00:03:51,480 --> 00:03:53,000
So that's fixed one error.

99
00:03:53,000 --> 00:03:55,850
What we're doing when we observe a change in the log data,

100
00:03:55,850 --> 00:03:58,530
is setting the new data to the Adapter.

101
00:03:58,530 --> 00:04:00,860
Our Adapter hasn't been set up to do that.

102
00:04:00,860 --> 00:04:02,550
We just created a new one

103
00:04:02,550 --> 00:04:04,480
in the earlier version of this app.

104
00:04:04,480 --> 00:04:06,760
We need to make a small change to the Adapter,

105
00:04:06,760 --> 00:04:09,970
so that it provides a way for its data to be changed,

106
00:04:09,970 --> 00:04:12,200
and I'm talking about the setFeedList function

107
00:04:12,200 --> 00:04:14,860
that we're calling on line 52.

108
00:04:14,860 --> 00:04:17,730
So let's do that now so that this code makes more sense.

109
00:04:17,730 --> 00:04:20,800
I'm gonna add it to the start of the FeedAdapter class.

110
00:04:20,800 --> 00:04:23,742
Let's go ahead and open our FeedAdapter class,

111
00:04:23,742 --> 00:04:24,920
and we're gonna add it there,

112
00:04:24,920 --> 00:04:26,350
before our getView.

113
00:04:28,330 --> 00:04:30,610
'Kay, so it'll be fun setFeedList

114
00:04:33,434 --> 00:04:35,267
parentheses feedList:,

115
00:04:36,504 --> 00:04:39,017
and we're defining a List of FeedEntryObjects there.

116
00:04:39,017 --> 00:04:39,850
FeedEntry.

117
00:04:41,509 --> 00:04:42,342
Close your parentheses,

118
00:04:42,342 --> 00:04:45,730
and open up a left and right curly braces.

119
00:04:45,730 --> 00:04:49,010
Then we're gonna type this.applications

120
00:04:49,010 --> 00:04:51,220
equals feedList.

121
00:04:51,220 --> 00:04:54,373
Then we're gonna do a call to notifyDataSetChanged.

122
00:04:56,030 --> 00:04:57,640
So that's pretty straightforward.

123
00:04:57,640 --> 00:04:59,630
It just replaces the applications List

124
00:04:59,630 --> 00:05:03,200
with the new data that we provide as an argument,

125
00:05:03,200 --> 00:05:05,400
but we have got an error on line 28

126
00:05:05,400 --> 00:05:07,570
because applications is a val in the constructor,

127
00:05:07,570 --> 00:05:10,680
and you can see that's defined on line 21.

128
00:05:10,680 --> 00:05:13,440
If we gonna change it, obviously we need it to be a var.

129
00:05:13,440 --> 00:05:15,553
So we'll go ahead and change it to var there,

130
00:05:16,980 --> 00:05:18,610
and that fixes that error.

131
00:05:18,610 --> 00:05:21,120
So that's the only change to our Adapter,

132
00:05:21,120 --> 00:05:22,750
and that should've fixed another error in MainActivity,

133
00:05:22,750 --> 00:05:25,120
so let's go back and check that.

134
00:05:25,120 --> 00:05:27,710
It has fixed that, but it's now giving us another error.

135
00:05:27,710 --> 00:05:31,560
So Android Studio is now objecting to passing feedEntries

136
00:05:31,560 --> 00:05:33,860
because that function wants a non-null type,

137
00:05:33,860 --> 00:05:35,760
and feedEntries could be null.

138
00:05:35,760 --> 00:05:38,240
Now, we've taken steps to make sure it isn't.

139
00:05:38,240 --> 00:05:41,150
We've initialised it, if you recall, to be an empty List.

140
00:05:41,150 --> 00:05:43,220
So there are a few ways to fix this.

141
00:05:43,220 --> 00:05:45,130
The easiest, and the one I like the least,

142
00:05:45,130 --> 00:05:46,980
is to use the bang bang operator.

143
00:05:46,980 --> 00:05:49,510
So we could do something along the lines of,

144
00:05:49,510 --> 00:05:51,310
we've got feedAdapter.setFeedList,

145
00:05:51,310 --> 00:05:54,060
feedEntries in parentheses, add the bang bang operator.

146
00:05:55,060 --> 00:05:57,020
We know here that it's safe to do that

147
00:05:57,020 --> 00:05:59,110
because we've made sure that our LiveData object

148
00:05:59,110 --> 00:06:01,110
will always contain a List.

149
00:06:01,110 --> 00:06:02,690
The Kotlin language is still evolving,

150
00:06:02,690 --> 00:06:05,750
and you may need to resort to using the two exclamations,

151
00:06:05,750 --> 00:06:08,250
the bang bang operator, from time to time,

152
00:06:08,250 --> 00:06:09,440
and that's especially true

153
00:06:09,440 --> 00:06:11,510
when using Kotlin with Java classes,

154
00:06:11,510 --> 00:06:13,300
and most of the Android framework, if you recall,

155
00:06:13,300 --> 00:06:14,980
is currently written in Java,

156
00:06:14,980 --> 00:06:15,980
but, in this case,

157
00:06:15,980 --> 00:06:18,720
I think it's safer to use the Elvis operator

158
00:06:18,720 --> 00:06:20,700
and pass an empty List if,

159
00:06:20,700 --> 00:06:22,410
and only if, feedEntries is null.

160
00:06:22,410 --> 00:06:24,820
So what I'm gonna do is duplicate that whole line there,

161
00:06:24,820 --> 00:06:25,920
well, those two lines,

162
00:06:27,210 --> 00:06:28,960
comment out one,

163
00:06:28,960 --> 00:06:30,830
and instead, we're gonna change that

164
00:06:30,830 --> 00:06:31,907
to use an Elvis operator,

165
00:06:31,907 --> 00:06:35,233
and so basically, within the parentheses for setFeedList,

166
00:06:36,107 --> 00:06:37,350
we're gonna put feedEntries,

167
00:06:37,350 --> 00:06:38,910
get rid of the bang bang operator,

168
00:06:38,910 --> 00:06:42,548
and put ?:, which is the Elvis operator,

169
00:06:42,548 --> 00:06:43,881
EMPTY_FEED_LIST.

170
00:06:46,000 --> 00:06:48,460
So basically, if feedEntries is null,

171
00:06:48,460 --> 00:06:50,350
we'll pass that EMPTY_FEED_LIST

172
00:06:50,350 --> 00:06:53,013
that we declared in our feedViewModel.

173
00:06:53,910 --> 00:06:55,810
So even though it would be safe here,

174
00:06:55,810 --> 00:06:57,810
I like to avoid using the bang bang operator

175
00:06:57,810 --> 00:06:59,210
as much as possible.

176
00:06:59,210 --> 00:07:01,300
That approach really does make sure

177
00:07:01,300 --> 00:07:03,320
that our code won't crash.

178
00:07:03,320 --> 00:07:05,130
Now, once you're happy with this,

179
00:07:05,130 --> 00:07:07,590
you may prefer to create your own LiveData

180
00:07:07,590 --> 00:07:09,313
subclass that can't return null.

181
00:07:10,750 --> 00:07:11,610
If you do a bit of Googling,

182
00:07:11,610 --> 00:07:13,870
you can find some solutions to that.

183
00:07:13,870 --> 00:07:15,080
One such solution

184
00:07:17,050 --> 00:07:18,323
that we found Googling,

185
00:07:20,380 --> 00:07:21,213
and it gives you a bit of an entry

186
00:07:21,213 --> 00:07:23,360
and a way there to actually resolve that,

187
00:07:23,360 --> 00:07:24,240
but, with that said,

188
00:07:24,240 --> 00:07:27,060
I suggest you stick with things like the Elvis operator

189
00:07:27,060 --> 00:07:29,800
until you're really comfortable with LiveData,

190
00:07:29,800 --> 00:07:31,700
and that's because creating subclasses

191
00:07:31,700 --> 00:07:33,420
of things that you're still learning about

192
00:07:33,420 --> 00:07:34,970
probably isn't wise.

193
00:07:34,970 --> 00:07:37,740
You can end up writing code that you don't fully understand,

194
00:07:37,740 --> 00:07:41,320
and that, in turn, makes debugging a nightmare.

195
00:07:41,320 --> 00:07:43,293
All right, so getting back to our code again.

196
00:07:44,520 --> 00:07:46,190
Back to MainActivity.

197
00:07:46,190 --> 00:07:48,010
We've still got some entries,

198
00:07:48,010 --> 00:07:49,330
or three errors rather,

199
00:07:49,330 --> 00:07:51,270
but luckily, they're all trivial to fix.

200
00:07:51,270 --> 00:07:53,610
Well, trivial apart from the other error that you'll get.

201
00:07:53,610 --> 00:07:56,800
So, our call to downloadUrl, though, first.

202
00:07:56,800 --> 00:07:58,186
That could be changed

203
00:07:58,186 --> 00:08:00,155
to call the downloadUrl function

204
00:08:00,155 --> 00:08:01,788
of our ViewModel instead,

205
00:08:01,788 --> 00:08:02,849
so instead of downloadUrl,

206
00:08:02,849 --> 00:08:03,682
it can be

207
00:08:04,579 --> 00:08:06,746
feedViewModel.downloadUrl.

208
00:08:07,870 --> 00:08:09,100
That's one, and there's another one

209
00:08:09,100 --> 00:08:11,040
down here in onOptionsItemSelected,

210
00:08:11,040 --> 00:08:12,760
so let's change this one down here,

211
00:08:12,760 --> 00:08:15,320
ignoring the error on line 89 for now.

212
00:08:15,320 --> 00:08:17,810
So feedViewModel.downloadUrl,

213
00:08:20,570 --> 00:08:23,630
but notice when I do that, unresolved reference.

214
00:08:23,630 --> 00:08:25,610
The problem we've got here is that feedViewModel

215
00:08:25,610 --> 00:08:27,460
is local to onCreate.

216
00:08:27,460 --> 00:08:29,333
We'll go back and have a look at that.

217
00:08:30,400 --> 00:08:33,580
We're to find that, on line 50, for onCreate, it's a local.

218
00:08:33,580 --> 00:08:35,610
We have seen how to fix things like this.

219
00:08:35,610 --> 00:08:37,740
We just move it into a class variable

220
00:08:37,740 --> 00:08:40,220
and then use a lazy delegate to resolve it.

221
00:08:40,220 --> 00:08:41,140
So let's go ahead and do that,

222
00:08:41,140 --> 00:08:42,690
so I'm going to cut this out

223
00:08:44,010 --> 00:08:45,413
of our onCreate function.

224
00:08:46,750 --> 00:08:49,280
Paste it in as a class variable.

225
00:08:49,280 --> 00:08:51,280
We're gonna make it, instead, a private.

226
00:08:53,780 --> 00:08:54,613
That's feedViewModel.

227
00:08:54,613 --> 00:08:55,760
Then we're gonna add a definition,

228
00:08:55,760 --> 00:08:57,040
so it's :,

229
00:08:57,040 --> 00:08:58,823
the type is feedViewModel.

230
00:08:59,830 --> 00:09:01,280
Then we need to type by lazy.

231
00:09:02,130 --> 00:09:03,560
Instead of the equal sign,

232
00:09:03,560 --> 00:09:06,730
we're going to add a left and right curly braces.

233
00:09:06,730 --> 00:09:09,210
We'll have the left curly brace there and the right one

234
00:09:10,110 --> 00:09:12,820
surrounding the code that we need to be called,

235
00:09:12,820 --> 00:09:15,200
and that's now defined, as you can see,

236
00:09:15,200 --> 00:09:17,310
and scrolling down, looking at our error now,

237
00:09:17,310 --> 00:09:19,180
we can see we fixed the error that was

238
00:09:19,180 --> 00:09:21,660
present there on line 93.

239
00:09:21,660 --> 00:09:24,410
We've still got an error here, though, on line 89,

240
00:09:24,410 --> 00:09:27,490
relating to trying to invalidate the URL.

241
00:09:27,490 --> 00:09:30,207
If you recall, our ViewModel has got a function to do that,

242
00:09:30,207 --> 00:09:33,440
and we've now got a reference to it that we can use.

243
00:09:33,440 --> 00:09:36,310
So let's actually change this altogether

244
00:09:36,310 --> 00:09:37,143
to be a call to

245
00:09:38,096 --> 00:09:38,929
feedViewModel

246
00:09:41,087 --> 00:09:41,973
.invalidate.

247
00:09:43,090 --> 00:09:44,340
That should've fixed all the errors,

248
00:09:44,340 --> 00:09:45,820
and we're just about done,

249
00:09:45,820 --> 00:09:47,870
but one strange thing that can happen

250
00:09:47,870 --> 00:09:50,780
is when we move the log TAG into the top level,

251
00:09:50,780 --> 00:09:52,480
as we did earlier in this video,

252
00:09:52,480 --> 00:09:55,970
sometimes, you can find that there's a weird import

253
00:09:55,970 --> 00:09:57,290
that Android Studio will add.

254
00:09:57,290 --> 00:09:58,123
It'll be something like

255
00:09:58,123 --> 00:10:01,800
import android.content.contentValues.

256
00:10:01,800 --> 00:10:03,350
So if that does pop up,

257
00:10:03,350 --> 00:10:04,320
you'll need to remove that

258
00:10:04,320 --> 00:10:06,310
because you'll have a duplicate entry for TAG,

259
00:10:06,310 --> 00:10:08,050
and that may be causing you some errors.

260
00:10:08,050 --> 00:10:10,400
In my case, I haven't actually got that error there.

261
00:10:10,400 --> 00:10:11,650
All right, so does it work now?

262
00:10:11,650 --> 00:10:14,200
We've now made changes to all our code,

263
00:10:14,200 --> 00:10:15,860
or to most of our classes.

264
00:10:15,860 --> 00:10:19,050
The time now has come to actually start testing the app out.

265
00:10:19,050 --> 00:10:21,650
So let's work on testing that app in the next video.

