1
00:00:03,740 --> 00:00:09,800
G'day everyone, welcome back. Okay we've got
the layout for our custom dialog.

2
00:00:09,800 --> 00:00:15,980
In this video, we'll see how to display it when
the user taps the about TaskTimer item,

3
00:00:15,980 --> 00:00:21,470
that's in the menu. MainActivity is
responsible for responding to menu items

4
00:00:21,470 --> 00:00:23,919
and we'll be adding the code in there.

5
00:00:23,920 --> 00:00:27,660
We're going to create a showAboutDialog function,

6
00:00:27,660 --> 00:00:31,720
and call that from our onOptionsItemSelected function.

7
00:00:31,720 --> 00:00:36,940
We'll start with a field to store a reference
to our dialog, which I'll add after the

8
00:00:36,949 --> 00:00:40,960
mTwoPane variable.

9
00:00:53,719 --> 00:00:59,690
If we're going to display the dialogue
in a showAboutDialog function, you

10
00:00:59,690 --> 00:01:04,580
may be wondering why we need to store a
reference to it in a field, instead of

11
00:01:04,580 --> 00:01:09,770
using a local variable. I've sort of
given that away with the comment. Okay,

12
00:01:09,770 --> 00:01:15,820
we'll call the function in onOptionsItemSelected,

13
00:01:19,920 --> 00:01:25,430
and we'll add the function immediately
below.

14
00:01:28,580 --> 00:01:34,200
This is pretty straightforward, after
what we've done so far with the dialogues.

15
00:01:34,200 --> 00:01:38,100
The difference when using a
custom dialogue is that we have to

16
00:01:38,100 --> 00:01:44,780
inflate the XML layout. That creates the
view that the dialogue will be displaying.

17
00:01:44,780 --> 00:01:49,980
Next we create an alert
dialog.builder object to do all the work

18
00:01:49,990 --> 00:01:55,780
of building our dialog for us. As I said,
I'll come back to why we're using a

19
00:01:55,780 --> 00:02:01,160
field aboutDialog, instead of just a
local variable.

20
00:02:01,160 --> 00:02:02,319
The setView function

21
00:02:02,320 --> 00:02:08,240
uses our inflated view as the dialogue's
contents, but you probably worked that one out.

22
00:02:08,240 --> 00:02:12,720
Then we call the builder's create
function to create the dialogue, and

23
00:02:12,720 --> 00:02:18,560
store a reference to it in our aboutDialog field.
Dialogues normally cancel

24
00:02:18,580 --> 00:02:23,799
when you tap away from them on the screen.
That's the default behavior.

25
00:02:23,800 --> 00:02:31,820
It's possible to change that by passing false to
 the dialogue's setCanceledOnTouchOutside function.

26
00:02:31,820 --> 00:02:34,660
If you want to prevent
your dialogue from being cancelled when

27
00:02:34,660 --> 00:02:40,820
the user taps away from it, that's how
you do it. Just pass false to this function.

28
00:02:40,820 --> 00:02:45,549
Remember they can still use the
back button, though. Our dialogue won't have

29
00:02:45,549 --> 00:02:50,560
any buttons, which is why I've explicitly
passed true to that function.

30
00:02:50,560 --> 00:02:56,079
Without buttons, the user won't have any obvious
way to dismiss the dialogue, if the

31
00:02:56,079 --> 00:03:01,480
default behavior changes. They'll try
tapping away from it and won't know that

32
00:03:01,480 --> 00:03:06,430
they have to use the back button. I
prefer not to rely on default behavior,

33
00:03:06,430 --> 00:03:12,160
if it's crucial to the correct
functioning of the app. Okay, next we set

34
00:03:12,160 --> 00:03:18,160
the title and the icon for the dialogue.
Calling the builder's setTitle and setIcon

35
00:03:18,160 --> 00:03:23,079
function is a correct way to do
this, but that comment sort of gives the

36
00:03:23,079 --> 00:03:29,590
game away. What we're doing here won't
work. I'll explain why and put it right

37
00:03:29,590 --> 00:03:34,120
once we've seen that it's not working.
The last bit of code displays the

38
00:03:34,120 --> 00:03:38,950
version information. We'll see where the
version number comes from after seeing

39
00:03:38,950 --> 00:03:44,170
the dialogue working.
Notice that we have to use findViewById

40
00:03:44,170 --> 00:03:50,050
here. we can't use a synthetic import
because we have to look for the IDs in

41
00:03:50,050 --> 00:03:55,150
message view. Watch out for that, because
your code will compile quite happily if

42
00:03:55,150 --> 00:04:00,880
you do use a synthetic import. It'll
compile but it won't run, and you'll get

43
00:04:00,880 --> 00:04:05,830
an error because the TextView
will be null. I'll say that again because

44
00:04:05,830 --> 00:04:12,010
it can be a tricky bug to find. If you
try to use synthetic imports to refer to

45
00:04:12,010 --> 00:04:17,779
views in a dialog, your code will compile
but it will crash when you run it.

46
00:04:17,779 --> 00:04:23,361
If you want to see that happening, change line 124.

47
00:04:23,361 --> 00:04:29,220
Copy and paste, comment out the first line

48
00:04:29,220 --> 00:04:37,140
and change aboutVersion to about_version. Android Studio adds a

49
00:04:37,140 --> 00:04:44,580
synthetic import of kotlinx.android.synthetic.main.about.*

50
00:04:44,580 --> 00:04:48,970
to the imports, and the code
looks fine. I'll swap the comments around

51
00:04:48,970 --> 00:04:54,120
and leave the incorrect line in the code.

52
00:04:57,780 --> 00:05:03,790
The function finishes by showing the
dialogue. We're getting a warning from

53
00:05:03,790 --> 00:05:10,100
Android Studio about passing null as the
route view. We've discussed that before.

54
00:05:10,100 --> 00:05:14,760
It's not normally a good idea, because
Android won't be able to apply styles

55
00:05:14,770 --> 00:05:21,070
and so forth to the layout. There are two
exceptions, and we saw the first one when

56
00:05:21,070 --> 00:05:25,120
the layout we were creating was the
root view, so there was no root to pass

57
00:05:25,120 --> 00:05:30,040
into the inflate function. The other
exception to the rule is here, when

58
00:05:30,040 --> 00:05:34,690
creating a dialogue. Dialogues aren't
part of the underlying activity. They

59
00:05:34,690 --> 00:05:39,730
display on top of it and are styled
separately. Once again, there is no root

60
00:05:39,730 --> 00:05:42,380
view that we could sensibly use.

61
00:05:42,380 --> 00:05:44,560
Those are the only times when you should pass

62
00:05:44,560 --> 00:05:49,600
null as the root view, when inflating a
layout. In all other cases, you'll have a

63
00:05:49,600 --> 00:05:54,340
view that you can use as the root and
you shouldn't pass null. I want to show

64
00:05:54,340 --> 00:05:57,010
you how to disable these lint warnings when you're

65
00:05:57,010 --> 00:06:01,889
absolutely sure that you know what
you're doing, and want to ignore them.

66
00:06:01,889 --> 00:06:08,130
I want to be completely clear here. This
isn't a way to deal with these warnings.

67
00:06:08,130 --> 00:06:13,690
Most of the time, you should fix the problem
that's causing them. It's very rarely

68
00:06:13,690 --> 00:06:17,800
that you should do what I'm about to
show you. The warnings are there for a

69
00:06:17,800 --> 00:06:22,300
reason, and just disabling them for a
quiet life is not an approach you should

70
00:06:22,300 --> 00:06:28,090
consider. Very occasionally, such as our
call to the inflate function, the

71
00:06:28,090 --> 00:06:34,000
warnings aren't relevant. It's okay to
disable the warning in cases like this.

72
00:06:34,000 --> 00:06:38,500
Click on the null argument in the call
to inflate, and then use the light bulb

73
00:06:38,500 --> 00:06:43,210
to get suggestions for how to respond to
the warning. The option I want to use

74
00:06:43,210 --> 00:06:48,820
here is the suppress option. That adds an
annotation to this bit of code, to

75
00:06:48,820 --> 00:06:54,160
suppress the warning in this place only.
Anywhere else that you try to pass null

76
00:06:54,160 --> 00:06:58,960
as the root view when inflating a layout,
you'll still get the warning.

77
00:06:58,960 --> 00:07:06,060
Choose the suppress option, and the annotation's
added to the code. That removes the

78
00:07:06,060 --> 00:07:10,540
warning from the function without
disabling it anywhere else.

79
00:07:10,540 --> 00:07:15,360
It's a useful way to prevent the warnings from
appearing, when you've made a deliberate

80
00:07:15,360 --> 00:07:19,880
decision to ignore them. That decision
should be an informed one, though.

81
00:07:19,880 --> 00:07:23,979
Don't just go disabling warnings when you
really should fix them. If you're

82
00:07:23,979 --> 00:07:28,660
wondering why you can't just ignore them,
you can get Android Studio to stop on

83
00:07:28,660 --> 00:07:33,060
each warning, when you check your code
into a version control system such as

84
00:07:33,060 --> 00:07:37,419
git, for example. That's a neat feature, as
it helps you avoid checking in poor

85
00:07:37,419 --> 00:07:42,130
quality code for your colleagues to
sneer at. But if it stops on warnings

86
00:07:42,130 --> 00:07:46,750
that you know you want to ignore, that'd
get annoying. Suppressing the

87
00:07:46,750 --> 00:07:52,000
warnings gives you a way to cope with
that situation. Our dialogue code's now complete,

88
00:07:52,000 --> 00:07:57,400
so run the app

89
00:07:57,400 --> 00:08:07,260
and use the About TaskTimer option in the menu to see it in action.

90
00:08:07,260 --> 00:08:19,020
In landscape mode, we use the information icon
on the toolbar to display the About dialog.

91
00:08:19,020 --> 00:08:22,200
Hopefully, you're not feeling too
underwhelmed right now,

92
00:08:22,210 --> 00:08:27,400
because I did warn you that the title
and icon wouldn't appear. Everything else

93
00:08:27,400 --> 00:08:32,500
looks fine, though, so we've just got to
fix those two items. Before going back to

94
00:08:32,500 --> 00:08:38,440
our code, tap away from the dialog and it
should disappear. The reason we haven't

95
00:08:38,440 --> 00:08:43,779
got the title and icon, is to do with
where in the code we're calling the

96
00:08:43,779 --> 00:08:50,110
setTitle and setIcon functions. If you call
them after creating the dialogue, they

97
00:08:50,110 --> 00:08:55,660
don't work. You don't get an error, they
just don't do anything. We need to call

98
00:08:55,660 --> 00:09:01,750
those two functions, before calling the
builder.create function. I'll copy those

99
00:09:01,750 --> 00:09:10,300
two lines to the clipboard, and paste
them in before the call to setView and create.

100
00:09:10,300 --> 00:09:15,160
I'll comment out the original
calls. That way you'll still have them if you

101
00:09:15,160 --> 00:09:23,340
download this source code. I'll remove this
comment and we'll run the app again.

102
00:09:23,340 --> 00:09:28,660
If we now check, we should get
the complete dialog appearing.

103
00:09:28,660 --> 00:09:35,589
I'll dismiss this dialog, rotate to landscape,
and check again. We're going to rotate

104
00:09:35,589 --> 00:09:45,320
back into portrait, but first, make sure
the log cat's visible.

105
00:09:45,320 --> 00:09:51,700
In fact, delete the contents so we can see anything that's
new. When I rotate the emulator with the

106
00:09:51,700 --> 00:09:57,600
dialog showing, we get an error.

107
00:09:57,600 --> 00:10:01,920
You'll probably have to scroll up to see it

108
00:10:03,480 --> 00:10:09,030
because it doesn't crash the app. Our app
doesn't crash, but obviously, something's

109
00:10:09,030 --> 00:10:12,940
not quite right and Android's logging an
error.

110
00:10:12,940 --> 00:10:14,520
The error is:

111
00:10:14,520 --> 00:10:21,500
activity learnprogramming.academy.tasktimer
MainActivity has leaked a window,

112
00:10:21,500 --> 00:10:27,810
that was originally added here. So, we've
got a memory leak because we're not

113
00:10:27,810 --> 00:10:32,850
dismissing our dialogue. A memory leak
happens when the Java garbage collection

114
00:10:32,850 --> 00:10:38,870
mechanism can't reclaim the memory and
other resources, that an object uses.

115
00:10:38,870 --> 00:10:44,300
A dialog that isn't dismissed is a good
example of how to leak memory.

116
00:10:44,300 --> 00:10:50,100
We should dismiss the dialog when our activity is
destroyed by Android. A good place to do

117
00:10:50,100 --> 00:10:54,930
that is in the onStop function. If
you're not sure why that's a suitable

118
00:10:54,930 --> 00:11:00,360
place, refer back to the activity
lifecycle video in section 4.

119
00:11:00,360 --> 00:11:05,010
We've already got onStop at the end of the
class. We added it just to see it being

120
00:11:05,010 --> 00:11:09,980
called in the logcat,
but now we've got a use for it.

121
00:11:13,500 --> 00:11:18,780
We check that the dialog's showing, using
a safe call in case it's null,

122
00:11:18,780 --> 00:11:23,520
and then dismiss it if it is showing.
That's why aboutDialog had to be a

123
00:11:23,530 --> 00:11:29,380
field rather than a local variable. We
need a reference to the dialogue so that

124
00:11:29,380 --> 00:11:32,500
we can dismiss it here, in onStop.

125
00:11:32,500 --> 00:11:35,900
Okay, now we shouldn't see that error in the logcat

126
00:11:35,900 --> 00:11:40,440
when the dialogue's showing and we
rotate the device.

127
00:11:50,170 --> 00:11:54,560
There's another couple of things I want
to talk about before we leave dialogues

128
00:11:54,560 --> 00:11:59,329
and move on. In the next video, we'll have
a look at where the version number came

129
00:11:59,329 --> 00:12:04,579
from in our dialogue. After that, we'll
test those links we added in the dialog,

130
00:12:04,580 --> 00:12:09,000
and see how to make them work on older
Android versions as well.

131
00:12:09,000 --> 00:12:12,040
See you in the next one.

