1
00:00:05,580 --> 00:00:09,630
Alright so let's have a look at the onPostExecute method now.

2
00:00:09,630 --> 00:00:15,180
Now we're going to do things slightly differently here to how we did it in the top 10 downloader app.

3
00:00:15,180 --> 00:00:16,190
now in the top 10

4
00:00:16,190 --> 00:00:23,110
downloader, our async task class was very tightly coupled to the other classes in the app.

5
00:00:23,110 --> 00:00:26,110
So I'm going to open that project so you can see what I mean.

6
00:00:26,110 --> 00:00:28,720
Now you may not be aware of this but Android Studio

7
00:00:28,720 --> 00:00:33,820
lets you have several projects open at once, although if you haven't got much RAM it may not be a good idea, but

8
00:00:33,820 --> 00:00:40,600
you can actually do it. So if I come up here to the file menu in Android Studio, I can select Open Recent, and

9
00:00:40,600 --> 00:00:44,290
I can see a list of the projects that I've opened previously.

10
00:00:44,290 --> 00:00:50,110
I'm going to select top 10 downloader, and if I hadn't worked with it recently I could have used the File 

11
00:00:50,110 --> 00:00:53,640
Open, and browsed to the project directory instead.

12
00:00:53,640 --> 00:01:00,040
Now we've got this prompt here, and Android Studio then asks if I want to open it in this window which'll close

13
00:01:00,040 --> 00:01:02,380
the current project, or in a new window.

14
00:01:02,380 --> 00:01:08,440
So I'm going to choose new window, so I can have both projects open at once, and by the way that can be useful,

15
00:01:08,440 --> 00:01:12,220
and you may want to do that so you can have my source code open at the same time as yours,

16
00:01:12,220 --> 00:01:18,450
if you're checking for problems. Alright so I'm going to click on New Window.

17
00:01:18,450 --> 00:01:23,010
Alright, so what do I mean when I say tightly coupled. Well firstly let's have a bit of a look here.

18
00:01:23,010 --> 00:01:28,740
I'm just going to close down some of these things. So have a look at MainActivity, and we come down here to the onPost

19
00:01:28,740 --> 00:01:35,900
Create, right down the bottom here, the onPostExecute method for our download data class.

20
00:01:35,900 --> 00:01:39,420
That's actually in here, it's our companion object, so onPost

21
00:01:39,420 --> 00:01:46,860
Executed as you can see here on line 134. Now what it's doing is that it's creating a parse applications

22
00:01:46,860 --> 00:01:52,260
object, and telling it to pass the data that was downloaded. Now that's fine,

23
00:01:52,260 --> 00:01:58,080
there's nothing wrong with that approach, but it does mean that downloading the data and parsing it, treat

24
00:01:58,080 --> 00:02:00,000
it as separate operations.

25
00:02:00,000 --> 00:02:04,830
In other words the same class that downloads the data also starts the parsing.

26
00:02:04,830 --> 00:02:10,500
Now even though it doesn't perform the parsing itself, it's still responsible for deciding what to do

27
00:02:10,500 --> 00:02:11,640
with the parsing.

28
00:02:11,640 --> 00:02:17,310
So it really can only be used for downloading RSS feeds in XML format, because attempting to

29
00:02:17,310 --> 00:02:22,290
use a parse applications object with any kind of data, will cause problems.

30
00:02:22,290 --> 00:02:27,480
So that's what I mean when I say tightly coupled. Although the main purpose of the download data class is

31
00:02:27,480 --> 00:02:29,010
to download data,

32
00:02:29,010 --> 00:02:35,550
it can really only be used to download XML data that conforms to the RSS specification.

33
00:02:35,550 --> 00:02:37,860
Now to give you an idea of why that's not ideal,

34
00:02:37,860 --> 00:02:43,500
the version of that download data class, in the previous version of the Android Java course that this

35
00:02:43,500 --> 00:02:50,940
course is based on, was used by nearly 40000 students. So as well as all the testing I did when developing it,

36
00:02:50,940 --> 00:02:53,800
it's also been extensively used by other people,

37
00:02:53,800 --> 00:02:59,160
so it's proven to be a reliable class. Now it'd be great to just lift it out of that app, and use the

38
00:02:59,160 --> 00:03:05,880
same class in this one because it's been proven to work, but because of that tight coupling, I can't use

39
00:03:05,880 --> 00:03:09,540
it to download our json data without making some changes,

40
00:03:09,540 --> 00:03:13,760
and as soon as I change it, it then has to be tested again in its new form.

41
00:03:13,760 --> 00:03:18,900
So in other words we lose the benefit of all those hours of testing that it had.

42
00:03:18,900 --> 00:03:20,730
Now in this case it's quite a simple class,

43
00:03:20,730 --> 00:03:24,390
so that's not a great hardship, but as you work on more complex code,

44
00:03:24,390 --> 00:03:27,300
it's worth keeping your classes uncoupled.

45
00:03:27,300 --> 00:03:32,430
That way they can be re-used when you need the same functionality in another app.

46
00:03:32,430 --> 00:03:37,620
So for our new app, our flickr app, we're going to write the rest of the download class a bit differently,

47
00:03:37,620 --> 00:03:41,940
to allow it to be used whenever we want to download any sort of text data.

48
00:03:41,940 --> 00:03:47,810
So I'm going to close this top 10 project, top 10 downloader project.

49
00:03:47,810 --> 00:03:54,930
So we're back now into the FlickrBrowser app, and specifically in our getRawData Class, and let's see what we

50
00:03:54,930 --> 00:03:57,030
can do differently in the onPost

51
00:03:57,030 --> 00:04:04,800
Execute function in this class. So this is the one that was responsible for the closed coupling in the top 10 downloader app,

52
00:04:04,800 --> 00:04:10,700
because it created an instance of the parser and also initialized the adapter for the list view.

53
00:04:10,700 --> 00:04:16,050
Now both of these had nothing to do with downloading data, which is what this class should focus on.

54
00:04:16,050 --> 00:04:22,800
So we're going to keep this class focused on just downloading the data. Before that though, I'm going to log the parameter

55
00:04:22,800 --> 00:04:27,480
we get, and then I'm going to run the program and I'm going to make sure that the doInBsckground method is working

56
00:04:27,480 --> 00:04:34,030
OK. I'm also going to remove the call to super dot onPostExecute,

57
00:04:34,030 --> 00:04:35,710
because it really doesn't do anything.

58
00:04:35,710 --> 00:04:38,420
And I can actually check this by holding down the command key,

59
00:04:38,420 --> 00:04:44,200
or control on a PC, and then clicking on this super method, so up here, in the onPostExecute,

60
00:04:44,200 --> 00:04:52,060
I can click on that to view the source code. So as you can see there, for the onPostExecute source code,

61
00:04:52,060 --> 00:04:56,240
there's no code to execute. The onPostExecute method's blank.

62
00:04:56,240 --> 00:05:01,780
Now there's also an annotation up here to suppress the unused declaration warning,

63
00:05:01,780 --> 00:05:04,810
let's see this on line 427,

64
00:05:04,810 --> 00:05:10,510
which is another good indication that this method in the async task base class doesn't do anything.

65
00:05:10,510 --> 00:05:16,800
So in other words it's there purely to provide the method for us to override. The async task will call our method

66
00:05:16,800 --> 00:05:22,120
if there is one, but there's no point us calling that super method, because in this case it's empty.

67
00:05:22,120 --> 00:05:25,000
Now it doesn't normally do any harm if you leave it in,

68
00:05:25,000 --> 00:05:29,060
but you'll see later why I've been pretty keen to remove it this time.

69
00:05:29,060 --> 00:05:33,760
So let's go back to the getRawData class in the onPostExecute.

70
00:05:33,760 --> 00:05:41,160
So I'm going to delete that line, and instead replace that with a logging line, Log.d parentheses

71
00:05:41,160 --> 00:05:51,730
TAG comma, double quotes onPostExecute called, parameter is and dollar result.

72
00:05:51,730 --> 00:05:58,240
Next we need to execute the async task from MainActivity, and specifically from the onCreate function.

73
00:05:58,240 --> 00:06:10,140
Let's go back to main activity, a bit more space here, so in onCreate, down here, after the setSupportActionBar line, we're

74
00:06:10,140 --> 00:06:27,380
going to type val getRawData is equal to GetRawData, parentheses, then getRawData.execute, and in parentheses,

75
00:06:27,380 --> 00:06:32,600
and in there what I'm going to do is paste in the link for the json feed that we had from our browser

76
00:06:32,600 --> 00:06:38,400
last time, and paste it in there because that's the argument that's going to be sent to the getRawData

77
00:06:38,400 --> 00:06:47,560
class, or specifically the execute function. OK, so let's run this app.

78
00:06:47,560 --> 00:06:51,650
Now we won't see anything on the emulator screen because it's still going to show Hello World, but we will

79
00:06:51,650 --> 00:06:58,010
be able to see things working in the log cat, starting with the security exception when I run the app.

80
00:06:58,010 --> 00:07:05,510
Let's actually have a look, look in our log cat, and we've still got our filter on.

81
00:07:05,510 --> 00:07:13,010
I'm going to take the filter off, because we also want to see the code in getRawData showing, and we can see

82
00:07:13,010 --> 00:07:18,120
now some of the logging, but we can also see this error, 'doInBackground Security exception Needs

83
00:07:18,120 --> 00:07:22,640
permission? Permission denied, missing Internet permission'.

84
00:07:22,640 --> 00:07:26,990
And after that onPostExecute called you can see that parameter is doing background, and we've actually got

85
00:07:26,990 --> 00:07:33,470
the message being returned there. So in other words our catch block's working to trap the permissions error.

86
00:07:33,470 --> 00:07:37,030
So to test the download I need to add the Internet permission in the manifest,

87
00:07:37,030 --> 00:07:41,760
so let's go ahead and do that. I'll open our manifest, double click it.

88
00:07:41,760 --> 00:07:47,430
Alright then from there, we're going to add our permissions as we've done previously, then above the applications line

89
00:07:47,430 --> 00:07:57,050
it's going to be, uses permission, and the name is going to be, we're going to just type INTERNET, and press enter there

90
00:07:57,050 --> 00:07:59,530
and we're going to close off that tag.

91
00:07:59,530 --> 00:08:04,100
Remember to select that from the drop down rather than typing it, to avoid any chance of problems

92
00:08:04,100 --> 00:08:08,420
coming up there, with errors, with mistyped name.

93
00:08:08,420 --> 00:08:12,710
Alright so I'm going to run this again now. We should make a bit more progress.

94
00:08:12,710 --> 00:08:21,540
Let's have a look, and the emulator won't do anything different but we'll be able to see some more output,

95
00:08:21,540 --> 00:08:28,250
and you can see now, some data there obviously being returned.

96
00:08:28,250 --> 00:08:30,630
And by the way if we want to clear up things to make it a bit easier,

97
00:08:30,630 --> 00:08:34,980
you've seen before how we can filter. We can use the pipe character to do a double filter so

98
00:08:34,980 --> 00:08:44,400
main activity, pipe, get raw data. That can be easier to only return the logging for the things that we're interested

99
00:08:44,400 --> 00:08:46,420
in looking at.

100
00:08:46,420 --> 00:08:51,770
And note if we scroll down to the bottom that not all data will be logged, because there's a limit on how much you

101
00:08:51,770 --> 00:08:53,180
can log in a single log call,

102
00:08:53,180 --> 00:08:57,560
but if anything had gone wrong with the download we'd have an exception, and we saw an example of an

103
00:08:57,560 --> 00:09:02,480
exception with a security exception, before we fixed that in the manifest.

104
00:09:02,480 --> 00:09:05,510
We don't need to see all the data to know that it is working.

105
00:09:05,510 --> 00:09:10,310
So in other words, at this point our doInBackground function's working. Now it's a good idea to test

106
00:09:10,310 --> 00:09:14,120
functions like this as you go along, that way if there's an error,

107
00:09:14,120 --> 00:09:16,710
you've already narrowed it down to a small bit of code, and

108
00:09:16,710 --> 00:09:19,390
that makes debugging a lot easier.

109
00:09:19,390 --> 00:09:25,670
Alright, so how do we keep the get raw data class uncoupled from the other classes in the app? So we know

110
00:09:25,670 --> 00:09:30,170
that at some point we're going to want to process the data that's been downloaded.

111
00:09:30,170 --> 00:09:36,800
If you want to decouple this class then the onPostExecute function isn't the place to kick off that processing.

112
00:09:36,800 --> 00:09:43,100
So what we really want to do is notify the calling class that the data's being downloaded, and somehow

113
00:09:43,100 --> 00:09:45,470
make the data available to it.

114
00:09:45,470 --> 00:09:51,430
So the basic idea is that the calling class uses get raw data to download the data from some URL.

115
00:09:51,430 --> 00:09:56,750
So get raw data then does the downloading, and when it's finished it calls the class back, using what's

116
00:09:56,750 --> 00:10:02,540
known as a callback method. Now that sounds a lot like what happens when a button gets tapped.

117
00:10:02,540 --> 00:10:08,720
The class that wants to know about the tap, creates an object that's got a function to respond to the click. The

118
00:10:08,720 --> 00:10:11,750
calling class then passes that object to the button.

119
00:10:11,750 --> 00:10:15,650
These are the onClickListeners that we've been creating to respond to button clicks

120
00:10:15,650 --> 00:10:22,470
in previous apps in this course, but here what we want to do is respond when the download is complete.

121
00:10:22,470 --> 00:10:28,610
So to see how this can work I'm going to create an on download complete function in main activity, and

122
00:10:28,610 --> 00:10:32,980
it's going to be called when the download finishes, and we'll do that part in a moment.

123
00:10:32,980 --> 00:10:39,590
But to start I'll just go back to main activity, and we're going to close down the manifest too for now. And we'll close down our

124
00:10:39,590 --> 00:10:45,230
log cat, and what we want to do is create this new function onDownloadComplete.

125
00:10:45,230 --> 00:10:49,430
So we'll do that in the bottom of the file,

126
00:10:49,430 --> 00:11:00,150
so fun onDownloadComplete parentheses data colon string status colon,

127
00:11:00,150 --> 00:11:08,340
and we'll use a DownloadStatus for that which is our enum, open a code block and the code is going to be, if parentheses

128
00:11:08,340 --> 00:11:16,420
status is equal to DownloadStatus.OK, code block. We're going to log it, so

129
00:11:16,420 --> 00:11:32,870
Log.d parentheses TAG, double quotes onDownloadComplete called, data is dollar data,

130
00:11:32,870 --> 00:11:50,600
else, download failed, Log.d parentheses TAG comma onDownloadComplete failed with status dollar status,

131
00:11:50,600 --> 00:12:01,360
error message is dollar data. So this function's got two parameters,

132
00:12:01,360 --> 00:12:06,910
the data, which may be an error message if things go wrong with the download, and the status.

133
00:12:06,910 --> 00:12:12,310
Now we're going to throw all this code away, but sometimes you have to do that while developing.

134
00:12:12,310 --> 00:12:18,040
I've created this function just to get things working, and see how it works, and once we've got the basic

135
00:12:18,040 --> 00:12:21,700
implementation working we'll change it quite a lot.

136
00:12:21,700 --> 00:12:26,940
Now developing small bits at a time like this, lets you test your code as you build the app up.

137
00:12:26,940 --> 00:12:35,260
Alright, so we now need to tell the get raw data class about this onDownloadComplete function so it knows to call it.

138
00:12:35,260 --> 00:12:39,820
Now we could add a method called something like, set download complete listener, or something along those

139
00:12:39,820 --> 00:12:46,180
lines, which is how the Android widgets do it. Now for a widget, it makes sense to have a separate function

140
00:12:46,180 --> 00:12:47,470
to set the listener.

141
00:12:47,470 --> 00:12:53,680
Because they can either be created in code, or by inflating XML, their constructor wouldn't be an appropriate

142
00:12:53,680 --> 00:13:00,070
place to set the listener, but get raw data is only created to download data, and it's got no user

143
00:13:00,070 --> 00:13:03,430
interface or anything like that to complicate matters.

144
00:13:03,430 --> 00:13:09,820
So in that scenario it makes sense to set the listener at the same time as we create the object, by passing

145
00:13:09,820 --> 00:13:12,370
the listener in the constructor.

146
00:13:12,370 --> 00:13:17,170
However many students struggle with this concept of call back functions.

147
00:13:17,170 --> 00:13:22,270
So what I'm going to do is start off, in the next video, in the same way as a button, by adding a

148
00:13:22,270 --> 00:13:26,020
setDownloadCompleteListener function, and get raw data.

149
00:13:26,020 --> 00:13:27,590
So let's do that in the next video.

