1
00:00:05,630 --> 00:00:11,120
In this video we going to add the code to display the full photo when one of the items in the recycler view

2
00:00:11,130 --> 00:00:13,640
list is clicked, or tapped, to be more accurate.

3
00:00:13,930 --> 00:00:20,080
So let's have a look at our diagram to see what we're doing. Now in the last few videos we finished

4
00:00:20,080 --> 00:00:25,670
the recycler item click listener, to let our app respond to clicks and long presses on the items

5
00:00:25,670 --> 00:00:27,250
in the recycler adapter.

6
00:00:27,560 --> 00:00:30,870
So we've implemented a lot of the functionality of this app.

7
00:00:30,870 --> 00:00:37,190
We just need to get the three activities working together to display the full photos, and allow the tags

8
00:00:37,190 --> 00:00:40,450
to be changed to search for different photos.

9
00:00:40,490 --> 00:00:43,050
So we're going to implement the search facility later,

10
00:00:43,280 --> 00:00:46,830
but in this video we're going to focus on displaying the full photo.

11
00:00:46,920 --> 00:00:52,460
Now in the process, we're going to review how to launch one activity from another using intents,

12
00:00:53,160 --> 00:00:55,870
and that's a fundamental aspect of Android programming,

13
00:00:56,100 --> 00:00:58,410
and one we first saw in the YouTube app.

14
00:00:58,460 --> 00:01:04,849
So let's get main activity to launch the photo details activity, when a photo is tapped in the list.

15
00:01:04,849 --> 00:01:11,090
So we're going to start by creating that base class, base activity, that our activities will extend.

16
00:01:11,360 --> 00:01:16,890
The reason for doing that is to share function and properties amongst the number of different activities,

17
00:01:16,940 --> 00:01:23,150
three in our case. By defining common functions in a single class, and then having the other classes extend

18
00:01:23,150 --> 00:01:26,880
it, they'll get access to everything that's defined in the base class,

19
00:01:26,970 --> 00:01:32,730
and that means we don't have to include the same function in each activity. They're only going to be sharing a single function,

20
00:01:32,840 --> 00:01:35,040
but it's still a very valuable technique.

21
00:01:36,330 --> 00:01:42,850
Alright so coming back to Android Studio, let's start by right clicking the package name - New Kotlin

22
00:01:42,850 --> 00:01:48,490
File/Class, Kind Class, and the name for the new class, we're going to go with BaseActivity.

23
00:01:48,850 --> 00:01:50,620
Now although this is going to be an activity,

24
00:01:54,180 --> 00:01:59,400
we're not going to be using the wizard, and that's because we don't want a layout created for it and we

25
00:01:59,400 --> 00:02:01,460
don't want it adding to the manifest.

26
00:02:01,530 --> 00:02:06,730
So the name as you can see is BaseActivity, and it'll be a class which I've selected, and I'm going to click OK.

27
00:02:07,230 --> 00:02:10,229
So this is for our activity base class.

28
00:02:10,289 --> 00:02:19,050
So for that reason I'm going to extend app compat activity, colon AppCompatActivity, and we also want

29
00:02:19,140 --> 00:02:27,580
a TAG as per normal, so private val TAG equals double quotes BaseActivity.

30
00:02:27,630 --> 00:02:32,850
Now I'm also going to define a couple of string constants that we'll use when transferring data between

31
00:02:32,850 --> 00:02:36,070
activities. Now when we launched new activities in the YouTube app,

32
00:02:36,270 --> 00:02:39,260
we didn't need to send any data between the activities.

33
00:02:39,540 --> 00:02:44,910
But in this app, when we want to display a photo in the photo details activity, we'll need to send

34
00:02:44,910 --> 00:02:50,010
the details of the photo to the activity that's launched, and you'll see how to do that and why we need

35
00:02:50,010 --> 00:02:56,530
these strings in a minute. So I'm going to start by typing internal const

36
00:02:56,640 --> 00:03:08,320
val flickr query is equal to flickr query in double quotes. Then the next one, internal const

37
00:03:08,950 --> 00:03:12,200
val photo underscore transfer

38
00:03:12,690 --> 00:03:16,190
equals double quotes photo underscore transfer.

39
00:03:18,570 --> 00:03:22,140
And actually want I should have done is define that outside of the class.

40
00:03:22,230 --> 00:03:23,330
So I'll go ahead and do that.

41
00:03:23,370 --> 00:03:28,820
I'll cut that out because it should have actually been outside, like so.

42
00:03:28,860 --> 00:03:34,110
Now I've made these constants internal because they don't have to be available outside this project.

43
00:03:34,120 --> 00:03:38,790
It's unlikely that we'd include this package in another, but it's a good habit to develop.

44
00:03:38,820 --> 00:03:42,690
Now we're only going to add one function to this base class.

45
00:03:42,690 --> 00:03:48,150
Now the function will be used to show the toolbar, and it'll also allow an activity to choose whether the

46
00:03:48,170 --> 00:03:51,380
toolbar should have the home button or not.

47
00:03:51,390 --> 00:03:56,720
Now main activity won't need a home button because it is the home screen, but the other activities will.

48
00:03:57,040 --> 00:04:02,880
So when we launch photo details activity from main activity for example, the home button will allow

49
00:04:02,880 --> 00:04:06,100
us to get back, or go back, to main activity.

50
00:04:06,410 --> 00:04:11,840
Now as you're typing this in, if you're prompted for the toolbar package to import, make sure you choose

51
00:04:11,850 --> 00:04:19,000
the support library, the Android dot support dot v 7 dot widget dot toolbar, and you should see that happens automatically

52
00:04:19,000 --> 00:04:22,970
as I'm typing. So I'm going to create that function.

53
00:04:23,100 --> 00:04:33,930
It's going to be internal, fun activateToolbar parentheses, and it's going to enableHome colon Boolean, and then we

54
00:04:35,420 --> 00:04:37,940
get a code block. And we'll start with a log,

55
00:04:37,980 --> 00:04:47,700
so Log.d parentheses TAG comma double quote dot activateToolbar. Then we're going to do val

56
00:04:47,880 --> 00:04:55,340
toolbar is equal to findViewById, and within the diamond operator we're going to do View,

57
00:04:56,270 --> 00:05:05,490
and within the parentheses it's going to be R dot id dot toolbar, closing parentheses as Toolbar with a capital T. And

58
00:05:05,490 --> 00:05:08,570
again this is where I said it's important to choose the correct import.

59
00:05:08,600 --> 00:05:11,080
So we want to choose the android dot support dot

60
00:05:11,120 --> 00:05:13,260
v 7 dot widget.

61
00:05:13,830 --> 00:05:21,110
OK, next we're going to type setSupportAction toolbar, toolbar,

62
00:05:21,450 --> 00:05:23,620
and then finally supportAction

63
00:05:23,630 --> 00:05:31,410
Bar questionmark dot set Display Home as up enabled, enableHome. 

64
00:05:32,580 --> 00:05:33,920
So that's actually the code.

65
00:05:34,170 --> 00:05:39,960
That's our base activity created, and actually I should have fixed that up as well, added a parentheses, or add a parentheses

66
00:05:39,960 --> 00:05:40,780
at the end of that

67
00:05:40,920 --> 00:05:47,580
to make that line valid, because we're obviously extending AppCompatActivity. So again that's all there

68
00:05:47,580 --> 00:05:52,770
is to base activity. It's created. The other activities in the app will extend this class instead of

69
00:05:52,980 --> 00:05:59,100
AppCompatActivity, so that they can use this activate toolbar function. And all the function does is inflate

70
00:05:59,100 --> 00:06:05,600
the toolbar from the toolbar dot XML file, then use the setSupportActionBar function with the inflated

71
00:06:05,610 --> 00:06:09,500
toolbar, to put the toolbar in place at the top of the screen.

72
00:06:09,570 --> 00:06:13,580
Now the action bar will automatically add the home button if we tell it to.

73
00:06:13,950 --> 00:06:18,950
And you probably guessed that we do that by getting a reference to the new action bar, and calling setDisplayHome

74
00:06:19,130 --> 00:06:26,120
AsUpEnabled to enable or disable the home button, depending on the parameter passed into the function.

75
00:06:26,130 --> 00:06:31,890
Now there's one other important change we need to make. Kotlin defaults to not allowing classes to be

76
00:06:31,890 --> 00:06:33,090
subclassed.

77
00:06:33,090 --> 00:06:35,540
Now we do want to extend base activity.

78
00:06:35,550 --> 00:06:37,680
That's the reason we're creating it after all.

79
00:06:37,860 --> 00:06:41,260
So to allow it to be extended, we have to go back and mark it as open.

80
00:06:41,280 --> 00:06:45,990
So we're going to do that on line 15, open to make it

81
00:06:46,110 --> 00:06:52,710
now able to be subclassed. Now if I just hover over that we're getting a warning over here, about

82
00:06:52,710 --> 00:06:55,320
the class not being registered in the manifest.

83
00:06:55,350 --> 00:06:58,710
That's actually why the class name itself's highlighted.

84
00:06:58,710 --> 00:07:00,840
Now the light bulb lets us suppress that warning,

85
00:07:01,010 --> 00:07:02,940
and that would actually be worth doing here.

86
00:07:03,220 --> 00:07:06,050
Our app won't create instances of base activity,

87
00:07:06,450 --> 00:07:08,360
so there's actually no point in registering it.

88
00:07:08,490 --> 00:07:11,400
So for that reason I suggest you actually use the toolbar,

89
00:07:14,930 --> 00:07:21,710
and select this option, suppress registered, so I'm going to click on that, and you can see that that warning disappears.

90
00:07:21,720 --> 00:07:28,270
And we've got this annotation at suppressed lint for registered. Alright, so now that we've done that, let's actually

91
00:07:28,270 --> 00:07:32,550
change the three activity classes and also do a bit of tidying up.

92
00:07:32,710 --> 00:07:33,980
So I'm going to start from the bottom.

93
00:07:34,030 --> 00:07:36,250
So let's open search activity first.

94
00:07:37,880 --> 00:07:39,010
I want to change this

95
00:07:39,020 --> 00:07:41,630
so I'm going to open up the import just so you can see what's happening.

96
00:07:41,630 --> 00:07:47,100
We should find, as I start removing some of these things, that the imports get updated.

97
00:07:47,160 --> 00:07:55,220
So firstly for AppCompatActivity, we want to remove that and make that BaseActivity.

98
00:07:55,290 --> 00:08:00,800
Now I've seen that the import's updated automatically, and we also want to make sure now that we've got a

99
00:08:00,800 --> 00:08:03,030
tag, so let's add a tag as well.

100
00:08:03,080 --> 00:08:10,170
So we'll do a private val TAG equals SearchActivity.

101
00:08:10,250 --> 00:08:12,950
And if Android Studio didn't delete the imports for you,

102
00:08:13,200 --> 00:08:17,630
then you want to go ahead and do those manually, but again because I've configured Android Studio to

103
00:08:18,470 --> 00:08:21,890
automatically remove unused imports, it did that for me automatically.

104
00:08:21,890 --> 00:08:27,250
Now in the onCreate method, we want to use the ActivateToolbar function to set the toolbar.

105
00:08:27,390 --> 00:08:32,809
So we want to comment out this setSupportAction toolbar line, and what we can actually do is just actually remove

106
00:08:32,809 --> 00:08:34,390
both of those lines.

107
00:08:34,940 --> 00:08:41,179
And instead what we want to do is call our function activateToolbar,

108
00:08:41,610 --> 00:08:43,440
and we want to pass true to this case,

109
00:08:43,490 --> 00:08:49,560
in this case, because we do want the home button to appear on the search activity, and we want to do a Log.d

110
00:08:49,570 --> 00:08:58,910
parentheses TAG comma double quotes, and it's going to be dot onCreate ends, and I didn't put one at the

111
00:08:58,910 --> 00:09:01,200
start so let's do that as well.

112
00:09:01,220 --> 00:09:03,890
First line there, starts.

113
00:09:07,390 --> 00:09:11,710
Now make sure that you do keep an eye on the imports and delete any unused ones that may get left

114
00:09:11,710 --> 00:09:12,130
behind,

115
00:09:12,130 --> 00:09:17,550
again, if you haven't configured your version of Android Studio to automatically reorganise imports.

116
00:09:18,030 --> 00:09:23,270
Alright so that's search activity. We need to do the same thing for photo details activity, so

117
00:09:23,290 --> 00:09:24,500
let's bring that on the screen.

118
00:09:28,070 --> 00:09:35,720
So firstly I'm going to change AppCompatActivity again to be BaseActivity, and I'm going to take the opportunity

119
00:09:35,720 --> 00:09:42,230
to clean the fab code up, because we're not going to be calling that anymore. I'm going to delete

120
00:09:42,230 --> 00:09:44,480
that, and also delete this set

121
00:09:44,470 --> 00:09:46,880
Action, setSupportAction toolbar.

122
00:09:47,220 --> 00:09:54,010
And instead what we're going to do is call the activateToolbar, passing true because again for photo details

123
00:09:54,290 --> 00:10:01,070
activity, we do want the home button to be an option so that we can go back to the main activity. So again

124
00:10:01,100 --> 00:10:03,080
tidy up any imports if necessary.

125
00:10:03,130 --> 00:10:06,740
So finally now, main activity, let's open that up.

126
00:10:06,930 --> 00:10:09,550
So we're going to start by replacing AppCompatActivity again,

127
00:10:11,600 --> 00:10:19,890
BaseActivity. We want our super and our set content view but we don't want the setSupportActionBar line there, I'm

128
00:10:19,910 --> 00:10:26,800
going to delete that. Instead what I'm going to do on that line and is do an activateToolbar.

129
00:10:26,960 --> 00:10:30,430
This time we want to pass false,

130
00:10:30,680 --> 00:10:34,760
and that's because we don't want the home button to appear, because we're already on the home page which

131
00:10:34,760 --> 00:10:38,600
is main activity. Now check the imports here as well.

132
00:10:38,610 --> 00:10:42,100
Now the synthetic import of activity underscore main isn't needed,

133
00:10:42,320 --> 00:10:45,380
now that we're not accessing the toolbar directly.

134
00:10:45,570 --> 00:10:51,420
At the moment here you can see we've just got content underscore main still showing. Android Studio won't always delete

135
00:10:51,440 --> 00:10:53,900
the import though, so keep that in mind.

136
00:10:54,170 --> 00:10:56,070
OK so that's the the housekeeping out of the way.

137
00:10:56,220 --> 00:11:01,630
It's time now to make our onItemClick methods, functions do something useful. At the moment

138
00:11:01,630 --> 00:11:04,690
if you recall, they're only just displaying Toast messages.

139
00:11:04,760 --> 00:11:10,640
So what we want is for a tap, or a long press of an item in the recycler view to launch the photo

140
00:11:10,630 --> 00:11:15,040
details activity, providing it with the details of the photograph to display.

141
00:11:15,530 --> 00:11:18,580
So we have to decide which of the two events to use,

142
00:11:18,860 --> 00:11:24,830
and for most applications, the onItemClick function's probably the one that users would expect.

143
00:11:24,830 --> 00:11:28,320
In other words they just tap the photo and it opens full screen for viewing.

144
00:11:28,410 --> 00:11:32,540
Now there are some apps where you might decide to use the long press instead.

145
00:11:32,570 --> 00:11:38,210
For example, a sat nav application aimed at motorcyclists. If you consider the use case for an app like

146
00:11:38,210 --> 00:11:45,260
that, the phone or tablet would probably be inside a waterproof case, fixed to the handlebars, and the rider

147
00:11:45,320 --> 00:11:47,150
would often be wearing thick gloves.

148
00:11:47,420 --> 00:11:48,970
So in a situation like that,

149
00:11:49,100 --> 00:11:52,640
the long press is a better option to make the app more usable,

150
00:11:52,850 --> 00:11:55,580
otherwise it's far too easy for the rider to trigger a

151
00:11:55,590 --> 00:11:56,920
tap when they didn't intend to.

152
00:11:57,410 --> 00:12:03,690
So the conditions that the app will be used in, will help to decide which touch event we should be using.

153
00:12:03,710 --> 00:12:07,330
So I'm going to use the long press, just so that we could be sure it works

154
00:12:07,340 --> 00:12:12,700
after our discussion in the previous video. And if you remember the long press function in the recyclerItem

155
00:12:12,770 --> 00:12:16,410
ClickListener, didn't return a true or false value.

156
00:12:16,430 --> 00:12:20,960
So this is actually a good opportunity to make sure it still works despite that.

157
00:12:21,410 --> 00:12:25,340
So we're going to modify the onItemLongClick function.

158
00:12:25,340 --> 00:12:29,810
So I'm just going to come down here, and you can see that we've got the code here. What I'm going to do

159
00:12:29,810 --> 00:12:34,750
first is get rid of the Toast message now because we're going to be using that anymore.

160
00:12:35,560 --> 00:12:43,010
And the code we want to introduce here is val photo equals flickrRecyclerViewAdaper

161
00:12:43,550 --> 00:12:53,180
dot getPhoto parentheses position. I accidentally added two parentheses there, it should just be the one. Then on

162
00:12:53,190 --> 00:12:53,680
the next line,

163
00:12:53,690 --> 00:13:07,400
if parentheses photo is not equal to null, code block, then we're going to do val intent equals Intent parentheses this comma,

164
00:13:08,220 --> 00:13:13,980
and it's going to be PhotoDetailsctivity colon colon class.java.

165
00:13:17,040 --> 00:13:27,400
On the next line we're going to put intent dot putExtra, putExtra parentheses, and it's going to be photo 

166
00:13:27,400 --> 00:13:31,770
underscore transfer comma photo.

167
00:13:31,810 --> 00:13:33,010
Then we're going to startActivity

168
00:13:35,820 --> 00:13:37,700
intent.

169
00:13:37,870 --> 00:13:45,700
Now we had to write the getPhoto function if you recall, that we're calling here on line 47, to return the nullable

170
00:13:45,700 --> 00:13:49,590
photo type, which means we need this null check which we're doing on line 48.

171
00:13:49,820 --> 00:13:54,970
And next we use an intent to launch the PhotoDetailsActivity.

172
00:13:54,970 --> 00:14:01,090
Now this is exactly the same as we did in the YouTube app, when we launched the standalone activity from a button

173
00:14:01,090 --> 00:14:02,360
on the main screen.

174
00:14:02,500 --> 00:14:08,170
So we create a new intent, then we use this as a context, this is the code on line 49.

175
00:14:08,830 --> 00:14:14,890
That's fine because this class extends BaseActivity, which itself extends AppCompatActivity,

176
00:14:15,100 --> 00:14:21,490
so our main activity class is an activity, and can be used whenever a context is required.

177
00:14:21,490 --> 00:14:24,760
Now the second parameter is the activity class that we want to launch.

178
00:14:25,030 --> 00:14:31,420
And remember that we put colon colon class dot Java after the class name, to create a class literal

179
00:14:31,630 --> 00:14:34,870
that we can use to pass the class as a parameter.

180
00:14:34,870 --> 00:14:39,970
Now the next thing we need to do before starting the activity, is provide the photo details to the

181
00:14:39,970 --> 00:14:40,750
intent.

182
00:14:41,020 --> 00:14:46,720
Now we didn't have any information to pass to the new activity in the YouTube app, but here we have to tell the

183
00:14:46,720 --> 00:14:53,110
PhotoDetailsActivity which photo it should display, and we can do that by using the putExtra function

184
00:14:53,350 --> 00:14:54,690
to add data to the intent.

185
00:14:54,700 --> 00:15:00,790
You can see we're doing that on line 50. Now putExtra can be used to add simple data such as integers and

186
00:15:00,790 --> 00:15:07,570
strings, but you can also send more complex objects, even photo objects. And it actually works very similar

187
00:15:07,570 --> 00:15:11,280
to the bundles that we used when saving the activity state,

188
00:15:11,390 --> 00:15:16,170
for when it's restored after an orientation change. So you need to provide a key and a value,

189
00:15:16,390 --> 00:15:21,070
then whatever needs to access the data, uses the key to retrieve it.

190
00:15:21,340 --> 00:15:26,990
So that's why we defined the photo underscore transfer constant in the base activity class.

191
00:15:27,010 --> 00:15:31,640
So both main activity and photo details activity need to use the same key,

192
00:15:31,780 --> 00:15:38,080
so we use a constant to make sure we don't type the key differently in one class. But we have got this

193
00:15:38,080 --> 00:15:40,450
error though as you can see again on line 50.

194
00:15:40,630 --> 00:15:44,710
Now I said that putExtra can be used to add more complex objects to the intent,

195
00:15:44,860 --> 00:15:49,060
but there is a condition that the object must meet for it all to work,

196
00:15:49,060 --> 00:15:51,350
and that object has to be serializable.

197
00:15:51,460 --> 00:15:56,290
So I'm going to stop the video here, and in the next video we're going to look at the serializable interface,

198
00:15:56,620 --> 00:15:57,950
and how to implement it.

199
00:15:58,270 --> 00:15:59,450
So I'll see you in the next video.

