(light electronic jingle)
In this section, we're going to create an app
that stores data in a SQLite database.
Now the app's gonna be a task timer
that we can use to record how long to spend
on different tasks.
It's useful if you have to complete
time sheets for billing customers for your work for example.
And it introduces some very important techniques
for Android programming including all the operations
you'll need to perform on the database.
Any databases will have separate tables to store
the tasks that we'll be timing and the timing's themselves
so that you'll be seeing how to add data
to a database when tables are joined.
Now more importantly perhaps, you'll also see
how to delete associated records in a joined table.
In this case if you delete a task,
then all the timings associated with that task
will also need to be deleted.
Of course it's good practise to warn users
that this will happen and the app will also
use dialogues to warn the user and allow them
to cancel the operation.
Although the focus of Android apps tends to be phones,
it's well worth considering tablet users
when producing your apps.
In this app, editing a task record on a phone
will show a different screen because there just isn't
enough room on a phone's display.
But on a tablet, users will be able to edit the task
details alongside the lists of tasks.
Now we achieve that by using fragments
and we'll also be seeing how to implement those fragments
in our apps.
Now another thing that this app will need to do
is record and display dates, and we'll be using
the Java calendar classes to do that.
Now it may seem like an easy thing to do,
but you have to be really very careful
when dealing with time.
Users can download your app from almost
anywhere in the world, and it's very easy to mess up
when dealing with different time zones.
So we're going to be looking at how to safely
deal with time across the world in your apps.
We'll also see another way to respond to events
from a recycler view.
And our list of tasks will include buttons to edit
or delete the task and we'll need to respond
to taps on the task itself to start and stop timing.
So let's have a look at the app running on an emulator.
So the first thing we do is provide the user
with basic information on how to use the app
when they first run it.
So this screen will show a list of tasks
that the user set up, but until they create some tasks,
the display would be empty.
And we've taken advantage of all that space
to give them some basic instructions.
So tapping on the plus icon up here in the toolbar
allows new details to be entered.
Now we've seen edit text hints before,
and they're a very useful way of letting the user know
when they should enter and what they should enter
into each field.
I'm gonna cancel that and go back home
and select abandon changes.
Gonna rotate the phone into landscape now.
I'm gonna tap on the plus option in the toolbar again.
Now the app is using fragments here and can take advantage
of the extra screen width to perform the editing
on the right hand side of the screen.
Alright, so I'm gonna enter some details here now.
I'm going to type task timer for the name.
Click on next.
Gonna type Android database app for the description.
And notice when I started typing that the Android
keyboard took over and in landscape,
each field is presented for editing.
And Android is also adding this next button
to move on to the next field.
So I'm going to add to zero here for sort order,
and that's how this app should appear
at the start of this list,
and then I'm gonna click on done.
And when I click on save over here,
the data saved to the database
and we've now got one task in our list.
So let's add another task now in landscape mode
and then we'll swing over to portrait
for the one after that.
So this is my Java course entry,
so I'm gonna type in Java course and click on next.
Description I'm gonna leave blank
and that's because the task name says enough.
So next and for sort order, I'm going to enter 10,
number 10, click on done, and then click on save.
Now the Java course task is sorting below the task,
timer task, and that's because task timer
had a sort order of zero.
Right, so I'll switch back to portrait now.
I'm gonna tap on the plus icon in the toolbar
to enter one more task.
Now because the screen isn't wide enough
to show the list and allowed data entry,
the fragments displayed by itself here in portrait mode.
Using fragments lets us write apps that automatically
adapt to extra screen space to give the user
a better experience.
Right, so the name for this task is gonna be cycling.
Now it's good to take a break from the computer now and then
so I'm gonna record how much time I spent cycling.
But that is a slightly vague name, so I'm gonna make
the description ride my bicycle.
And in portrait mode there's enough space to display
the edit text and the keyboard as you can see,
so Android doesn't have to present the fields one by one.
Now the data is not saved, which means it'll be lost
if we use the home or back buttons to return
to the previous screen.
So I click on back, so what I'll do is come up here
and just fix the top right there.
So I click on back.
So to prevent the loss of data, we're showing a dialogue
here so that the user knows they're about
to lose data if they continue.
In my case I want to save those changes so I'm gonna
choose continue editing.
So I'm going to leave the sort order blank
and it should default to zero.
That means that this task will sort to the top of the list
and if two tasks have the same sort order,
then they'll appear alphabetically.
So when I click on save we can see that cycling
is at the top.
Now to start timing a task we just long tap it,
I'll do that now.
The heading changes to show which task
is currently being timed.
Now if we were building a customer for this task
or any of the tasks, we probably wouldn't be interested
in charging for every second, so I'll stop timing that now.
And if you go into settings,
and we've got options here to ignore timings for tasks
that last less than a certain amount of time.
Now you've probably seen sliders like this before,
but what's not obvious is just how much control
you can provide by using them.
In most applications dragging the slider
would increase some value in a linear fashion.
It would really make a lot of sense here.
If you wanted to ignore timings less than five minutes,
that's 300 seconds and you'd have to drag the slider
a long way to get that high.
But this slider is a little bit different though.
I'm just going to tab to it now,
and I'm gonna use my keyboard just
to show you the increments.
So as we start off you can see the increments
are five seconds and that is true
until we get to 55 seconds.
After that though if I do another one,
notice how it's now jumped to one minute,
then it counts in five minute increments
until it gets to 15 minutes, then the next time
it goes to 30 minutes, then to 45 minutes,
then it jumps to one hour, then the next
increment is two hours.
So you can see that we can provide a lot of flexibility
without having to clutter the screen up
with all sorts of different sliders.
And we'll be seeing how to create a slider
like this in this app as well.
So I'll move that slider back to zero now,
otherwise we'd have to wait a long time
to get any real timing data to display in the reports
that we're about to look at.
Now this settings menu also lets us choose which day
a week starts on.
Some companies start on a Sunday
when they're doing accounting, others start on a Monday.
So tapping the day here brings up this list of days,
which is a dialogue where you can
choose the day of the week.
And it's probably a bit pointless including
the other weekdays in this app, but this is a good
example of how to choose one of a range of options,
and for that reason all the weekdays are included.
So I'm going to make my week day start on a Monday.
Alright, so I'm gonna click on back now
to go back to our list of tasks.
Alright, so let's start another timing for my Java course.
And you can see that showing on the screen there.
Now I could just long tap that again to stop it,
but if I want to actually swing over to another task,
I can long tap that task and it ends the timing
for the Java course and starts the timing for the cycling.
Alright, so that's enough cycling
and I'm going to long tap that to stop it.
It's time to get back to work.
So the second icon in the toolbar up here,
that's used to display reports of how long
was spent on each task.
So this duration's report, I'll open it now,
has got two different layouts for portrait and landscape.
In portrait mode we can see the task name,
the date, and how long was spent on each task.
In other words, the duration.
But whenever I take the device back into landscape
again there now, we also get the description
showing as well.
Now you can sort the lists by clicking
on the column headings.
We can see the timings and task order
or by clicking on the description column here,
the description heading rather, you can see
that it's now sorted by description.
We can also display for weeks or just single days
but with any two timing records
that's not easy to demonstrate.
This is a good time though to show a bug
in the programme though.
Now at the moment we're viewing a full week's data.
There's only data for today and because I've only
just done some timing.
The button on the toolbar up here shows a one
to indicate that it was switched to just showing
a single day.
So when I tap that, it changes to a seven
as you can see on the screen there now
to indicate that tapping it again would display a full week.
But what's actually happened to the data?
It was there in the week view
and should be appearing for today.
Well it's very easy to get things messed up
when you're dealing with dates and times across the world.
I can see the timings that were there
by using the calendar icon by clicking on that
and choosing the previous day, choosing yesterday,
in my case it's the 12th.
Click on okay and the entries actually appear again.
And there's the timing data back.
Now I selected yesterday in the calendar,
but the date column over here is still
showing today's date.
So the reason for that is I'm recording this in Australia
which is currently nine and a half hours ahead
of Greenwich Mean Time, GMT.
Because I'm recording this early in the morning,
it's still yesterday effectively at Greenwich.
Unless you specify otherwise, times are in GMT,
Greenwich Mean Time.
That's going to have serious implications
for most parts of the world including places
like the UK and Portugal that use GMT.
In summer, both those places change there clock
to Summer Time.
So we've got an app here that works sometimes
in some parts of the world,
but won't work all the time anywhere.
Well that's not quite true, it'll work all the time
in Casablanca and the Azores where they stay on GMT
all year round.
But overall though, that's not good
and you'll get a chance to fix this
towards the end of the section.
And yes, I did say you.
But don't worry though, we'll be covering
the problem and solution before the challenge.
Alright, so I'm going to go back to the main
task screen now and the menu up here
has also got a generate option
that we can use to generate test data.
So I'm gonna click on that and it'll make our reports
a bit more interesting, and you can see that
it's completed already, depending on the speed
of your computer it may take a while.
This menu option won't appear though
in the release version of the app.
There's some code that checks to see
if we're running in debug mode,
which you are when you're running
directly from Android Studio as I am
that makes this option visible.
The code though hasn't got any frills,
it's really only there to generate data for use
while we're testing so that we don't have to wait
while we create hundreds of timings.
Now if we were going to do something like this for users
then you should run it as a background thread.
Because in my case even though it was relatively fast,
the emulator appeared to hang.
You may find that the display's gone blank
for example on earlier versions of Android.
The point is though that the app was very definitely
blocking the user interface, which was not a good thing.
So this generate data option generates between
100 and 500 random timing records
for each of the tasks that exist in the database.
So it will take a little while, but it's much quicker
than us having to create the data ourselves.
And actually it's a bit slower than it should be
because the method that generates the random data
also logs what it's doing in the log cap.
So though the emulator screen looked like there
was nothing happening, if I quickly bring up Android Studio,
we can see that there's quite a few entries there showing
details about the actual timings
that were actually generated.
Alright, so I'm gonna close it down here,
back to the emulator.
Alright, so now that I've finished
we're going to go back to our reports again.
Clicking on the icon.
Now the reports sorted by name, then date.
But we can group all the cycling tasks together
by clicking on the task name heading like so.
Now the first button on the toolbar,
that's a switch between displaying a whole week
or just the current day.
Now at the moment it's showing a whole week's
worth of data, but clicking on the one button
swaps to just showing today.
And if you're doing this in America
within five to eight hours of midnight
you'll be seeing tomorrow's timings.
And that's because the USA is behind GMT.
And as we saw earlier, the button icon
also changes to reflect the fact
that clicking it again will show a week.
And again, I've got that same situation
there with the bug that I've talked about,
with the GMT bug, so I have to go back
and click on the previous day to actually get
my data to display on the screen.
Alright, now we have seen that calendar,
so I click that calendar again there now.
This time I'm gonna go back about a month now.
I'm gonna go back to May, we'll say May the 16th.
Click on okay there.
If I come across here now and click on the icon,
the seven button now, the app should work out
which seven days will be displayed based on the data
I just chose and which day we've set
for the first day of the weeks in the settings.
That's easy to see there now.
If I click the date heading firstly to sort that,
you can see we've got entries from the 14th,
16th, 17th, and 19th of May.
And just to confirm if we go over
and click on the calendar,
that is correct because I chose Monday
as my start of the week and that's the 14th,
and we can see Sunday was the 13th there
and we've got no entries showing for the 13th.
Cancel out of that.
So basically we're seeing data here
from the 14th through to the 19th, which is correct.
And that's obviously assuming there's data
for each day of course, and if we didn't
have that bug that I've talked about.
Now the version of the app is currently
displaying dates in the American format,
month, day, year.
That can be confusing for people in other countries,
so we'll also be seeing how we can display the dates
in the user's preferred format based on their country.
Alright, so finally now there's an option
to delete old data.
So we get to choose a date and everything
before that date will be deleted.
So I'm going to choose the 16th here,
so I'm going to click on the menu option,
select delete old timings,
I'm going to choose the 16th, click on okay.
It asks us for confirmation.
So we get a prompt here making sure that we really
do want to delete all that data.
And if I cancel it the data will still show.
But if I go back to the option,
select delete old timings,
select the 16th of May, click on okay,
click on okay again, and you can see now that
the data prior to the date that I've selected
has now been deleted.
Well that's the theory at least,
it was actually a bug in the programme,
but fixing that is also going to be a challenge
towards the end of the section.
Alright, so we'll go back now to our main list again.
So there's two buttons we can use to edit
the task details and delete the tasks.
So when I click the delete button over here,
the trash icon next to the Java course,
there's a dialogue option that pops up here
warning that the timings will also be deleted.
So our timing's data is stored in a separate table
that links to the tasks table,
and there's no point keeping all the timings around
if you no longer know which task it relates to.
So the database has been set up with a trigger.
When a task is deleted or the timing's records
with the same task ID are automatically deleted for us,
and we'll be seeing how to do that as we write
the app as well.
So I'm gonna click on delete here now.
It deletes that, and now if we go back
to our reports, we shouldn't see any other
entries related to the Java task
because it's been deleted.
Going back to the previous week again,
there's nothing related to Java actually
showing them in the list any more.
Right, so go back to the main task list again.
Now the app's also got an about dialogue
in the menu in the main screen,
so we'll click on the button there.
An about screen is a good place to provide
additional information about the app
and we'll how to include clickable links
in our screens.
So here I can click on the link here
to launch the Android browser.
You can choose one.
I needed to go through the initial defaults
and then it will then load that web page automatically.
And when I close the browser notice that we get
back to our application again.
And we'll be seeing how to do that as well.
Now I can't demonstrate the email link,
we just go back again and have a look.
There's also an email link there,
I can't demonstrate that because I don't have
the email set up on this Android emulator,
but on a physical device, tapping the email address
will launch your email programme with the to address
already filled in ready for you to type an email.
So our previous dialogues had okay and cancel buttons,
but this one's just got an okay button,
so I can click on that to close that down.
So that's our app, its basic functionality
may be quite simple, but we're going to be learning
a lot of useful techniques when we write this app.
And we'll start by looking at the underlying
database which we'll do in the next video.