(upbeat music)
Alright, so we added two
more menu items in the last video.
Now we need to write the code
to make these menu items work.
So we're going to go back to main activities,
I'm going to close down this design.
The feed on manual XML
(mouse clicks)
Go to my main activity.
Bring it on the screen,
And we need to add the new items
in the on options items selected function.
This one here.
Now this takes a bit of thought,
because these two options are going to
keep most of the euro unchanged,
they just alter the limit perimeter.
So that means we have to store
the base part of the yearout
as a class variable
rather than a private variable.
Now at the moment,
we've got to feedUrl
private in the onOptionsItemSelected method.
So we need to move it into the class
so we that we can use it's value
from one quarter to the next
as different limits are chosen.
And we also need to store the current limit size,
so I'm going to add two variables
to the top of the class.
So what I'm going to do also is
just take a copy of that
feedUrl.
Well actually I'll cut it out of there,
Go back up to the top of the class,
and just below the tag,
you're going to put the code in there.
Tidy this up a little bit,
I'll put it below the download data,
So instead of just val now
it's going to be private.
(typing)
It's going to be a ver,
equals, and we're going to get the
default value in a minute.
For the next line we need to add this feed limit
so I'm going to set that to private var
feedlimit = 10.
Alright so then we're going to take a copy,
of this line at the top of the application
We're just going to copy that.
Let's paste it in our feedUrl.
But, instead of where it's got 10,
you'll change that to percent d.
That's a lower case d.
Now, this is a way of specifying an integer value
that's going to be replaced by an actual value
using a string dot format function.
Now, the string dot format function takes a string
containing special format codes like we said d
and a number of values that are used
to replace the format codes.
You can do the same thing
by concatenating strings using plus.
But, this is a bit later.
Alright and to avoid duplicating the Url,
I'm going to change the oncreate code
so that is uses these two fields
to create the Url that's downloaded initially.
So, to do that we're going to come down to oncreate method.
We're going to change the download to euro method core.
Going to delete out that hard code
feed euro we have to replace that with
feedeuro
.format
feedlimit
(typing)
So, that now uses the string dot format method
to replace the percent d in the feed euro
which we added on line 37
with the current value of feed limit.
The other thing that we're going to do
is with our on options item created,
we also want to fix that there as well.
So, let's do the same thing.
Now I'm going to take a copy of that,
that line that download euro line.
Come down here, we're going to replace it there.
The other thing we need to do
is we need to replace the percent d in three places
in our on options item selected.
So let's do that.
Percent d.
Percent d
and percent d.
Alright, so that's done.
And, all we have to do now
is change the value of feed limit
when one of the two menu options is chosen.
So, to do that we need another brant in our when expression.
So, let's go ahead and do that.
We're going to put this before the else.
So, down here.
And what we're going to type
is r.id.mnu10
,r.id.mnu25
arrowtoken right blockade block
and then we're going to put our logic in here
to define whether to select 25 or 10.
We'll do that by putting if not item.ischecked
not is checkable but is checked.
Then we put item.ischecked=true
so if it's not checked
we're setting it equal to checked.
In other words we're setting it to true to do that.
And we're going to put
feedlimit=35takefeedlimit.
Then, we're going to do a log
so a log.d(tag,"onOptions
(typing)
itemselected, we'll put a colon there space
a dollar sign left to right curly brackets
item.title left side of the curly brackets setting
feed limit to dollar feed limit.
Then we'll put an else there.
Let's just copy that line to save a bit of time.
(typing)
And this time, will be onOptionsItemSelectedItem feed limit
and because it's an else, there wasn't any change
so we're just going to put the text unchanged.
So, we want them to perform pretty much
the same actions whichever of the two options is selected.
The only difference here is that
the new value assigned to feed limit.
And, you can see here that there's a neat little way
to toggle between two different numerical values
and that's just to subtract the current value
from the sum of the two.
So, in other words, 35 minus 25 is 10
and 35 minus 10 is 25.
So, that's how the limit changed here.
Now, if an item was already checked
then we don't need to do anything.
Let's just test here on line 72.
But, actually what we're doing we're making sure
that it's not checked.
So, if it's already checked we're going to ignore that
and then the else code will be handled.
And then we'll actually go through and just log some output
to say that this setting of feed limit was unchanged.
Otherwise, if the radiact button wasn't already selected
or checked in other words,
we're actually checking it and then we're updating
feed limit then we're logging that output as well.
Now, the way these radiact groups work
isn't immediately obvious but it's actually quite clever.
The menu items aren't checked or unchecked
by the menu system when you click them.
You have to do that yourself in code.
So, if either one of those options is selected from the menu
then we test the item to see if it was already selected.
If it was, we don't need to do anything else
or I'll have logged the fact that you can see
with the else on line 77,
so that we can see what's happening by checking the log cat.
But, if the item wasn't checked,
then we're setting it to checked.
Now, the menu system does help here,
it will automatically uncheck any other members
of the same group for us.
And that's handy because we only going to reference
the one item passed into the method.
And incidentally, that's why android passes
in the item reference rather than just it's id.
So, we have an item to manipulate when we need to
like we're doing here.
Now, if you want to you can find out more information
about menu option groups in the documentation.
Let me just bring that up on the screen.
(typing)
Now, this guide on screen actually covers
quite a lot about using menus in general.
The bit that's specific about groups
is pretty well towards the bottom.
About 4/5 of the way down.
There's a section that should be there called
something along the lines of using checkable menu items.
(silence)
See the card Using checkable menu items.
Alright, so check that out
if you want to find out more information.
Alright, so let's go back to our app.
So, essentially the app should toggle between
showing the top 10 and top 25
now that we've introduced as code.
So, let's actually run it and see what happens.
(clicking)
Alright, so it starts off showing the top 10
and what we can do is, we'll just scroll down
and just confirm that it is the top 10.
We're getting google maps to be the last one there.
If you change this now to top 25.
And have another look while scrolling down.
Clearly, there's more applications showing now
so that's good that the top 25 is now running as well.
And we can also if we want to confirm that,
have a look at log cat.
And confirm that the change did actually occur.
We can see the data being downloaded there.
Just scroll up above that.
Top 25 setting feed limit to 25.
Let's make it easy, we can filter our main activity.
Let's do that.
Main activity.
So, you can see now onOptionsItemSelected Top 25
was selected and feed limit was set to 25.
And just to confirm that,
if you go back and set it to top 25 again.
You can see this time, Top 25 setting feed limit unchanged.
So, it's logging the fact that the limit wasn't changed.
But, there is a problem though.
And that's that it downloads the data again
even though nothing's changed.
And we can see that here,
the fact that it's started the asynctask.
Now, that's a good way to drain the device battery
or incur roaming data charges.
So, we really should do something about that.
Now, by thinking back to the activity life cycle,
you should be able to work out what will happen
when I rotate the device into landscape.
What I'm going to do is just clear the log cat
so that we can see the log entry
so download data will pass applications.
Going to remove the filter to main activity.
Actually I'll clear the log cat again
now that I've done that.
Now let's go and open up the app
or bring that back onto the screen and let's rotate that
and see what happens.
So, when I do that you can see from the log cat here
that it downloads the data again.
And that's because the activity's destroyed and recreated.
But, also if we come over here and check out the code,
you can see what's happened here
is that it set the limit back to 10,
rather than 25.
And that's again because the activities
got destroyed and recreated.
But, we know how to fix that by storing the value in these
to state bundle is in the instant state function.
Now, ideally the code should store the last used Url
and only download the data again
if the Url is actually changed.
If we do that, we need to provide some way
for the user to refresh the data manually.
But, at least then, they'd be able to make
a conscious decision to use their mobile data
or use up some of the battery life
rather than our app just doing it anyway.
Unfortunately though, saving something as complex
as an adapter, isn't as straight forward as just storing it
in the instant state bundle.
And that probably wouldn't be the best approach anyway.
If we wanted to save performing a download
with a device orientation changed.
It's probably better to cache the downloaded data
in the same way that web browsers do.
So, that way you can allow your activity
to be destroyed and recreated when the device is rotated
and the redownloading would read the data
from the local cache instead of over the internet.
Now, that's a bit much for only the 3rd app in the course.
So, this app's just going to download the data again
when the device is rotated.
But, if you do want to learn more about caching downloads,
there's a pretty decent Google article,
which I'm just going to bring up on the screen to check out.
(clicking)
And basically, we can prevent redundant downloads
when menu items are clicked though
and can also make sure that the correct Url
and feed limit are used when the device is rotated.
So, that sounds like a good challenge.
Now, one problem you'll have that I haven't covered
is how to set the current menu limit
once we've restored the feed limit value.
Now, the place to do that
is in the OnCreateOptionsMenu method.
Now, the approach is very similar
to working with widgets in a layout.
But, here we're working with items in a menu.
So, let's actually have a look at that.
So, OnCreateOptionsMenu, you've got the menu.flatline
and what we want to do after that
is put in some code that says if
feed limit is equal to 10
then we're going to do a menu question mark
find item
R.id.mnu10 question mark outside of the parenthesis
.ischecked is equal to true,
we're going to add an else otherwise.
And the else is going to be basically very similar
but it's going to be the r and the mnu25,
so the top 25 button.
So, your else will be
menu question mark.find item parenthesis r.id.mnu25
then a question mark outside of the parenthesis
.ischecked equals true.
And then we just kind of return to what it was before.
So, we used the menu.finditem method
then set the ischecked property to check
either the mnu10 or mnu25 item
depending on the value of feed limit.
Now, notice that we're using the safe call operator
a lot here.
Menu is a nullable type, so we have to use safe call
when calling it's finditem method.
And we also use it before accessing the ischecked property.
Now, you might be wondering why I didn't just change
the function signature, after all I've been doing so
with apparent appeal up until now.
Well, as I said, you need to think very carefully
before doing that.
Now in here, we can't be certain that we can do it.
So, our app could use one of the no action bar themes
which means it wouldn't have a menu.
So, in that case menu would be null.
Now, it's likely that OnCreateOptionsMenu
won't be called in that case.
You'd have to examine the android framework code
to be sure which would take some time.
So, it's easier just to use safe calls,
at least in this scenario.
If in doubt, don't modify the framework's signatures.
Now, of course if Google added a non-null annotation
then you'll know that we could've changed it.
When that happens the code generator will generate
the method without using a nullable type.
Alright, so with that change, you should now be able
to have a go at the challenge.
So, here's the challenge.
So, you want to modify the apps,
so it doesn't download data from the same Url a second time
unless the user specifically chooses to refresh the data.
Now, you also store the current Url and limit
so that they aren't reset
when the device orientation changes,
the data will still be downloaded again
to follow the change in orientation.
But, it should download from the same Url
that the user was looking at before they rotated the device.
So, to be clear, the only three events
that should cause data to be downloaded
are firstly, a change in orientation.
Secondly, selecting a different Url or limit from the menu.
So, if the same menu Url or limit is selected from
the menu a second time, the data wouldn't be downloaded.
Thirdly, if the user chooses to refresh the feed,
with the refresh menu option
that you're going to actually add.
And just as a hint there,
review the Activity Lifecycle before restoring
the data from the bundle.
Now, there's more than one way to achieve this challenge.
So, the real test here is just that the app works.
Alright, so I'll go over my solution to this
in the next video.