All right, so we're now ready
to start writing the code to make
our calculator calculate.
Now, we should have the calculator project open,
we're gonna be editing MainActivity.kt,
so what I'm gonna do is just to close down
the ActivityMain, 'cause we don't really
need that open any more,
come over here and close that down,
then we're gonna click on the Project pane
and then we come down here and open the Package
under app, java then the Package name,
academy.learnprogramming.calculator,
and double-click MainActivity.
You wanna make sure also that you're
also in the Android view.
All right, so there's our class, our MainActivity.kt.
Now, all the activity does at the moment
is display the layout on the screen.
Now that's taken care of by Android
when we pass the layout's ID to SetContentView,
here on line 10.
Now, Android will then be watching the buttons
but as we haven't attached any code to them,
nothing will happen when we tap the buttons.
Now, it's probably a good idea to think about
what we want it to do,
so let's actually have a look at some flowcharts
describing how the app will work.
Now, this is the main part of the programme,
you can see on screen, and we've already
got the code to display the layout on the screen.
So it's that call to SetContentView
that will display our activity called MainLayout.
So next we need to perform some initialization,
and this will find all the buttons
that we're interested in, and then set
their OnClick listener so that
they actually do something when they're tapped.
The programme will then wait, waking up each time
the Android Framework calls one of the listeners
that we've set, that's the button click process
after the initialization.
Now, once a button is clicked,
we need to decide if it was one of the digit keys
or the decimal point, in which case
we just append it to the number on the screen,
or if it represents an operation
to perform on the numbers.
Plus, minus, multiply, divide or equals.
Now, the flowchart shows a decision being made there,
but that's a representation of how the logic works
and doesn't directly correspond
to how we're gonna code it.
In place of a test to see what kind of button
was clicked, we're going to assign one or two
different listeners to the different types of button.
So the digits and decimal point buttons
will have one OnClick listener
and the operations button will have another.
Now, the flowchart is accurate,
but when you see one of those decision diamonds
in a flowchart, you generally expect to see
an if statement in the code,
but we'll be implementing the decision
by attaching different listeners to the buttons instead.
Now, the digit and decimal point listener
is going to be very simple.
It just reads the caption on the button
and appends it to the number that's being built up
in the EditText on the screen.
When one of the operation buttons is tapped,
it'll just read the number from the EditText,
then check to make sure there actually was a number there.
If there isn't and the EditBox is empty,
the operation is stored as a pending operation
and the programme goes back to waiting
for another button to be clicked.
And it will also update the little TextView on the left
with the symbol for the operation that was tapped,
just to remind the user what arithmetic operation
will be performed when they press the equals button.
And if there was a number, the programme will perform
whatever operation was pending,
and then display the result.
So as you can see on this slide,
the programme will allow you to do things like
three plus 50 minus two times eight,
and update the result after each stage.
So when you type the three, it will appear
on the display, when you press plus,
there's nothing to add to three so the
pending operation becomes plus.
Once you've entered 50, the minus button
will cause the plus operation to be performed
and the result, 53 in this case, will appear in the result.
Now the pending operation will then be minus.
After two is entered, the multiply button
will cause the subtraction to be performed,
the result of 42 will be displayed
and the pending operation will then be multiply.
And once eight is entered, nothing will happen
until another operation key, including equals,
is tapped, then the new result will be displayed.
All right, so that looks fairly straightforward,
so let's go and add the code.
All right, so we're gonna start off with fields
to hold the references to the three widgets
that will be updated or read.
And also some variables to store the operands
and the pending operation.
So let's go ahead and do that now.
So we've got our various code in there,
I'm just gonna expand the import
so we can see what we're doing here,
and just below to class activity line on line six,
we're going to add a line here, it's gonna be private.
Space var, result.
Space, colon.
In EditText, equals null.
Now Android Studio's showing an error on line eight.
If we hover over it, "Null can not be a value
of a non-null type EditText."
Now, Kotlin does this as much as possible
to protect us from null pointer exceptions,
and by default, properties and variables in Kotlin
can't be null.
Now that's really great for preventing
null pointer exceptions, but it means
that we have to change the way we think slightly,
if you're used to Java.
So, we can't just not initialise it
because Kotlin won't allow that.
So just to show that, if I remove
the equals null on the endthere,
we also get another error, "Property must be
initialised or be abstract."
Now, with a Java mindset, we could just
declare result to be a nullable type,
which we do by adding a question mark after the name.
So I can come back here out of the EditText
and put a question mark, and set that equal to null.
And that indeed does get rid of the error,
but now we lose all the protection
from null pointer exceptions that Kotlin provides.
Now, marking variables as nullable is sometimes valid
and we're gonna be doing that shortly.
But unless you've got a good reason for doing this,
then it should be avoided.
So the problem we've got is that we have to
initialise result to something,
but we can't get the reference to our EditText widget
until the OnCreate method executes.
Now, the Java solution of initialising it to null
isn't actually good practise in Kotlin.
Now, fortunately, the designers of the Kotlin language
have thought of this, and they provided
the lateinit keyword as one way to handle this situation.
So what we can do is come back up here
and for our definition, we can put private,
and before the var, we'll put lateinit,
their result in EditText, and I'll get rid
of the question mark equals null on the end there.
And you can see the error's disappeared there.
And what that does, it tells Kotlin that
we're using a non-nullable variable,
but that we're gonna defer giving it a value until later.
So lateinit, as you probably will have figured out,
is short for late initialization.
Now, if we attempt to use result
before giving it a value, the app will actually crash.
Now currently you'll get a Kotlin.unitialized
property access defection.
Although the documentation's a little bit vague
about the exact exception,
so we should probably rely on that exact exception
in our code, but that's no problem,
because you wouldn't want to catch that exception,
you'd fix the problem after finding it during testing.
Okay, so that's one way to solve the problem.
And I'm going to use this same lateinit approach
for the next widget, the other EditText,
which I'm gonna call newNumber.
Let's go and create that, so private, lateinit,
var newNumber: and EditText again.
So lateinit's very useful in cases like this,
but keep in mind it can only be used
with var properties, in other words,
that's properties that are read and write.
Now sometimes, that's fine, we may want to
make result refer to different EditText widgets
while the code runs.
In that case, lateinit is probably
the best way to define it.
But in this app, the references to
our widgets won't change,
and that means that in Kotlin,
we should consider declaring them as val,
rather than var.
If that doesn't mean much to you then
review the Kotlin tutorials earlier in this course.
All right, so another way to declare our widget references
is to use a lazy delegate.
So I'm gonna show you how to do that,
we're gonna write some code now, on the next line,
private val displayOperation by lazy,
then we need left and right curly braces,
and within them we're gonna put findViewByID,
you have the parentheses, but before the parentheses,
you wanna have two diamonds, or a diamond
as you can see there, left and right signs,
and then in there we're gonna type TextView,
then in parentheses, we're gonna put r.id.operation,
let's put a space there so it's a bit more readable.
Now when using this by lazy, you're defining a function
that'll be called to assign the value to the property.
Now, the function will be called the first time
that the property's accessed, then the value is cached,
so that the function isn't called again.
That's pretty cool.
So, as long as we don't access DisplayOperation,
until onCreate has been called, this'll work fine.
And it has the advantage that DisplayOperation
can be declared as val, which can make
code more robust for properties that won't change.
Now, there's no reason why I couldn't have used
the same approach for all three variables,
in fact, we probably should, 'cause there's no reason
result and newNumber can't be declared as val.
But I've done it this way to show you the options,
and while you may have to use lateinit,
rather than the lazy delegation.
Now, there are other ways of handling this
and we'll see another alternative shortly.
Kotlin development for Android is still fairly new,
and developers are still working out
which approaches to settle on.
Google for instance don't yet have
a style guide for Kotlin, at least not
at the time of recording this video.
When they do, you'll probably be able to find it
at this address, and I'm just going to put that
on the screen there for you,
well, I'll actually just open a browser.
So when they do release one, which I'm sure
they will in time, it'll probably be at this address.
Github.com/google/styleguide, all one word.
And you can see there, if we actually scroll down,
there's various languages that they actually
talk about in there, Java, C++, Python and so forth,
but at the time I'm recording this,
there isn't a guide for Kotlin.
You can see there's nothing seems to be
starting with Kotlin, I'll just do a quick search,
nothing there, but I would say in time,
almost certainly they will release
a style guide for Kotlin.
And once we've finished this app, what I'm gonna do
is change it to use another way,
then you'll see three different ways of
dealing with this situation,
and you can understand code regardless
of the approach you use.
Right, I'm just gonna go back to Android Studio.
Now, one thing to note is that the lazy function
is thread safe.
That means that if the DisplayOperation property
is accessed by code in two or more threads simultaneously,
the function will still only be called once.
Now, don't worry if that doesn't make sense,
we'll be talking about background threads
later in the course.
For now though, it's enough to use the modified version
that I'm just about to enter.
Now, our activity class can't be accessed
by more than one thread, so there's actually no need
for the extra overhead that lazy includes by default.
So, when you're just using it in an activity,
as we are here, then you can add
an extra parameter to disable the thread safe code.
And I'm going to do that now, so after this by lazy,
we put in parentheses, then we type in
lazyThreadSafetyMode.none, or I'm choosing that
from the drop-down.
And everything else will be as it was before.
Now as I said, don't worry too much
about that at this stage, you probably do
want to add that lazy threadSafetyMode.none argument
to lazy whenever you're using it in an activity
like we are here.
And if you need thread safety in your properties,
you'll know, and all of this will
make a lot more sense later.
All right, so moving on now, we also need
to make some variables to store the numbers
that we're gonna be using in our calculations.
Let's go ahead and do that.
And I'll just make a note here.
I've put these outside variables to hold the operands
and type of calculations.
And the ones that we want here,
private var operand1: Double, capital D,
question mark equals null,
and I'll just type the other two
and then we'll talk about these.
Private var again, operand 2, colon, this is also
gonna be a Double, no question mark this time equals 0.0.
Or a period, whatever you're used to calling it.
Private var pendingOperation equals, in double quotes,
an equals sign.
Now, I mentioned earlier that we'd be looking at
a nullable variable, and the declaration
of operand1 shows how to specify that it can be null.
To do that, you just put a question mark
after its type, as you can see I've done there,
on line 14.
Now, the reason Why we're allowing operand1 to be null
is that we need to record whether it's been given
a value or not.
Now, when the app's first started,
there won't be a number to perform calculations on,
and our app needs to allow for this,
so that it knows when the number that the user enters
is operand1, or operand2.
Now, what a null value for operand1 signifies
that the user hasn't yet given it a value.
And you'll see how to make use of this in a moment.
The important thing is that null is a valid
type for operand1, so we're deliberately
declaring it as a variable that can be null.
Okay, so moving on now, to the OnCreate function,
we need to find our widgets, and store the references
to them in those three variables.
And we also need to do that for the 16 buttons.
So let's go ahead and do that now.
So I'm going to add this code after the super.onCreate
and after the SetContentView calls.
So the first one is going to be result
is equal to findViewbyId, that's gonna be
r.id.result, as you can see,
I'm selecting from the drop-downs.
Then newNumber, that's equal to findViewById,
and that's gonna be r.id.newNumber,
again, we're using the IDs that we defined
when we were creating our layout.
So next we need to add definitions
for our data input buttons.
So I'm just adding a comment to that effect.
We start with val, button0, colon,
Button with a capital B equals findViewById, r.id
And it should be button zero.
Then what I'm going to do is just copy
one for the rest, so button one, two, three, four,
five, six, seven, eight, nine,
we'll also do the dot, so let's go ahead and change those.
And the last one we'll call buttonDot,
and this is gonna be then nine, eight, seven, six,
five, four, three, two and one.
Now you'll know if you made a mistake there,
because if we typed something that doesn't exist,
you 'll get this red flag.
So these, getting these IDs and the IDs we defined
when we were creating the layout
earlier in this section of the course.
All right, so that's our data input buttons there now,
and we also need to store references to our
operation buttons as well.
So, let's make a comment about that,
so, Operation, our son's, making a bit more space here.
So we've got button equals.
findViewById, and in the diamond I'm going to put button.
Subtitle button, that's gotta be r.id.as a button equals.
Let's do the same for the divide button.
Multiply minus and plus.
So, first one is going to be divide,
divide, next one, we'll do multiply.
Let's just do these last two as well.
We also want the minus and then
finish off with the plus.
And on the left-hand side, let's fix that as well.
So plus will be the first one,
minus for the next one,
Then multiply, and that should be it.
So we've got equals, divide, multiply, minus and plus,
and equals, divide, multiply, minus and plus
on the right-hand side.
And by the way, we're only referring to the button widgets
inside this onCreate method, and so there's no need
to create properties for them,
and that's why we've done that as opposed
to the other ones that we created our
properties outside, fix up that typo,
outside the method.
Now, we're using the Android findViewById function
to get references to the widgets in the layout,
but note that we don't need to do that
for the operation widget.
The findViewById function will be called the first time
we access DisplayOperation, so we don't need
to find it in our OnCreate function.
And that's this lazy delegate function that
we defined here on line 12.
Basically, that's the lazy delegate at work.
Now, blank lines in the code also help to separate
the two distinct groups of buttons
and to make our code more readable.
And I've also included a comment to show
the differences between the two sets.
Now, the first group of buttons are used
to enter the miracle values
that we'll be performing our calculations with.
The second group of operations that we can perform
on those values, the add, subtraction, multiplication,
and so forth.
Now, Kotlin can't work out the widgets' type
from the call to findViewById,
that just returns a view object,
which could represent any type of object.
So we need to provide Kotlin with a clue
to the type of widget that we're expecting.
Now I've done this in two ways,
in the first group of buttons,
I've done that by specifying the type of each widget
that's the colon button that's part of the declaration,
but another way to achieve the same thing
is to specify the generic type that findViewById
will actually return.
And to do that, we specify in the type parameter
in angle brackets, as you can see here on line 40.
Now, you wouldn't normally mix the two ways of doing this,
and you certainly shouldn't mix them
in the same function,
but I've done it here to show both ways,
there's no advantage to either so pick one you like
and stick with it and be consistent.
Now obviously if you work for a company
that has a style guide, and they specify
one method or the other, then you'd use the approach
that they are suggesting in their style guide.
I would normally suggest using Google's style guide
as a pointer, but as I've pointed out,
they haven't produced one yet.
All right, so at this point we now need to
set a listener on the buttons so that they'll
do something when they're tapped.
Now, in the button click counter app
there was only one button, so we used
an anonymous in a class to set its listener.
But here we're going to assign the same listener
to multiple buttons, so we're gonna give
the listener a name for that reason.
Gonna come down here and code that in the
OnCreate function.
We're gonna type val listener is equal to
View.OnClickListener, then in the
left and right curly braces, we're going to type
v then a dash and a greater than sign,
press enter and type val b = v as Button,
with a capital B.
Then it's gonna be newNumber, the next line,
newNumber.append (b.text).
Okay, so what've I done there?
Well, the variable listener holds a reference
to a new OnClickListener instance,
and its OnClick method just reads the caption
of the button using the Text property,
then appends it to any text already in
the newNumber EditText widget.
Now, when a button's tapped, and the
Android Framework calls the onClick method,
it passes in a reference to the button that was tapped.
Now remember that all widgets are views,
so any widget that's tapped can be passed
as a parameter to onClick as an instance
of its base class view.
Now, not all views can have text,
so before we refer to the Text property,
we have to actually cast B as a widget that does
have a text property.
In this case, that's a button because we know
we're attaching this listener to buttons.
Now, B isn't a very good name for a variable,
but in a short function like this, two lines,
it's not worth spending any time
to come up with anything more meaningful.
Definitely don't use names like that
for variables that have a wider scope,
or that exist in more complex functions
with many lines of code.
All right, so the next step is to assign
this listener to each of the 11 buttons,
from zero to nine and the decimal point,
so that it's called when one of them's clicked.
So to do that, we need to, on the line below,
for each one, button, whatever the button is,
button0.setOnClickListener and we're going
to type in listener as the argument,
and we'll do the same for the other buttons,
so we've got buttons one through nine
and then also we've got
Dot, then we've got nine, eight, seven, six, five,
four, three, two, one and obviously button zero was
the first one that was set.
Now I guess if you wanted to be clever,
we could have stored all the button variables
in an array and looped through it
to set the listener instead of copying each line
like I've done.
But with only 11 buttons, it probably wouldn't save
any lines of code, but if I was implementing
a full keyboard, then I'd certainly look
at doing something like that.
Now, we should now be able to run the programme
on an emulator and make sure the buttons
work as they should.
But this video is getting a bit long,
so let's actually look at doing that
in the next video.