TOMMY MACWILLIAM: In this video, we're
going to write our first Android app.
Our last video introduced us to a
bunch of Java syntactic constructs.
And now we're going to use those to
create an Android app with some user
interface elements.
So there's a few more concepts
to dive into before we
start writing our first Android code.
The first is the Android build system.
So we've actually used this
already in our last video
just without really
learning too much about it.
The Android build system is
called Gradle, which is actually
an open source project you can use to
build any type of Java application,
but it takes care of a bunch of
things like downloading libraries
from third parties you might
want to use and compiling things
from Java into byte code.
So we're going to be modifying
some Gradle files as we
make some of our Android applications.
The next is another general software
engineering concept called MVC.
So MVC stands for Model View Controller.
And it's a general design
pattern that advocates
separating out your logic,
particularly of your app,
into three different pieces.
The first piece is called the model.
And you can think about the model
as the data that your app needs.
So if you're displaying a
list of items, for example,
you might want to have
a model that represents
each item in the list
or the list itself.
In our last video, we
created that track class.
That's basically a model,
because it's modeling some data
that our application is going to use.
On the other side of-- sort of the
opposite of the model is the view.
And you can think about the view as just
how your data is going to be displayed.
So the model doesn't say anything
about how the data looks in your app
or how it's used.
It just says here's the data itself
and here's how it's structured.
On the other hand, the view says
there's some data out there somewhere,
I don't know what it
is, but here's how we're
going to display that
data when we do have it.
And lastly, the C, or
controller, is sort of the bridge
between the model and the view.
So the controller might
say, OK, I'm going
to go grab some data from
somewhere, get back some models,
and send it to the view.
And then the view might say, OK,
someone just tapped on this button.
The control will say, OK, great,
let's respond to that button tap
and maybe do something
and update some model.
So these three different components,
we're going to work with all three
of them when writing an Android app,
where the model is going to be the data
we're using.
The view, a lot of this is
going to be provided by Android.
We don't need to write our own buttons.
We can just use the buttons
that Android provides.
And then the controller
is where we're going
to put a lot of our application
logic to sort of bridge those two
things together.
A few other concepts that
are sort of Android specific.
One is called activities.
So we actually have
already seen an activity.
If you remember in that
last app, we had something
that extends AppCompat activity.
And activity is sort of your base
class for a screen in Android.
So every time that you
look at an Android screen,
and maybe you're navigating
from one to another,
those are often different activities.
And it's called an activity, because
each screen basically represents
one thing that you're trying to do.
So for example, in your
contacts app, the first activity
might be a list of all of
the contacts in your phone.
And then when you select
one, the second activity
might be all of the information
about just one single contact.
So each of those would be
represented with different classes
and maybe their own models and views.
Next is resources.
And you can think of resources as all
of the other stuff in your Android app
that isn't just Java code.
So one example of a type
of resource is a layout.
So a layout in an Android app is going
to describe how a view should look.
And layouts, under the hood, are
defined using something called XML.
And if you've used HTML
before, they're really similar.
XML is essentially just a
more general version of that.
But you'll have tags and you'll define
a tag using that left and right bracket.
So here, I've created a
tag called linear layout.
And my tag has one child.
And that child is called a text view.
And these are both happen to be
things that Android defines for me.
This linear layout tag says, inside of
this is going to be some list of views,
I'm going to lay them
out either horizontally,
one to the right of the other, or
vertically, one on top of each other.
Then this text to view is also an
Android view that's defined for me.
And it's this pretty simple
view that just displays text.
And so inside of this
text view tag, I have
something that's called an attribute.
And so this attribute, its
name, is android: text.
And its value is hello.
And this attribute name is special.
It means something to Android.
And in this case, it just
happens to be the text that's
going to be displayed in your app.
Now you'll notice at the
end of this text view tab
I have this slash followed
by the greater than.
And that basically says this tag
doesn't have anything inside of it.
There's no children for this tag.
That makes sense, because a text
view is just sort of one view.
Doesn't really make sense to put
other views inside of this text view
if we're just displaying simple string.
And then lastly, we're closing
this linear layout tag.
So we're saying there's nothing
else inside of our layout
other than this one text view.
And so as we're writing
views for our Android app,
we're going to be writing
XML that looks like this,
where you'll often have layouts, which
sort of represent containers for views.
And then you'll put views
inside of those layouts.
And Android will
automatically lay them out
on the screen in a way that makes sense.
Another concept we'll see shortly
is something called an intent.
And an intent is a
special object that's just
defined somewhere in the Android SDK.
And it represents a way to go
from one activity to another.
So an intent is going to specify
things like, which activity should I
open next, what's the class that
corresponds to that activity,
as well as any data you might want
to pass in between activities.
So if you have one activity
where a user selects something
and you want to take that selection
and display it in a second activity,
the intent is how you would
pass that data back and forth.
So we'll see that shortly.
And finally, we're going to be writing
something called a recycler view.
And a recycler view is a really, really
common class in a lot of Android apps.
And it basically represents
anything that's a list of items.
So a lot of those infinitely
scrolling lists, something like,
Twitter is using a recycler view
to show your list of tweets.
Your phone application
is using a recycler view
to show a list of
contacts in your phone.
They're sort of the bread and butter
of a lot of mobile applications.
But all they do is really
take some list of items
and display them on your phone.
What's nice about a recycler view is
you might have a list of 1,000 things
that you want to display, but there's
no way that all 1,000 of those things
are going to fit on your screen at once.
So a recycler view has
some nice optimizations
built into it to dynamically put the
right things in memory for your screen.
So rather than loading everything
into memory and all of those views
into memory, which might be a lot
and may be too much for your phone,
it's only going to load in the things
that are displayed on your screen,
you know, plus or minus a few.
And that's going to help keep
your apps memory usage down,
so it's not super slow and
can run on all devices.
So that's it for all the concepts we're
going to use in our first Android app.
So let's dive in.
So I'm back in Android Studio.
You'll notice that my
emulator is still running.
I like to leave it running because it
can take some time to startup sometimes
and there's no harm
in leaving it running.
So I'm going to come back over here
and click Start a new Android Studio
project.
Just like before, I'm going to
start with an empty activity,
since I'm going to
write everything myself.
And now we know what activity means.
It's just that one screen
in our application.
The application that we're going
to be writing today is a pokedex.
So we're going to take
some list of pokemon,
let the user browse through
them, and when they select one,
go to a second screen that displays some
more information about that pokemon.
So for our name, we're
going to call it pokedex.
Again, remember that this package
name is just some, often domain name,
backwards.
Doesn't really matter
what you pick here,
so we're just going to
say eduHarvardCS50Pokedex.
We have where we want to save it.
I'm just putting it on my desktop.
We're going to use that
same minimum API level
as before, just targeting Android 5.
It's up to you what you want to target.
And then make sure we're using those
AndroidX artifacts to use the latest
version of the Android Support Library.
So we're going to click finish.
And just like before, Android Studio
is going to automatically generate
some files for me.
But this time let's
actually walk through what
Android Studio has generated.
So I'm going to come
over here on the left
and I'm going to start with this
file called AndroidManifest.xml.
I'm going to double
click that to open it up.
And this is the first
xml file that we've seen.
So we've just looked at
what that xml syntax means.
So we can see here that
we have some root element.
Element is called manifest.
And this is just specifying to
Android what our package name was,
just to make sure we can launch it.
And then we have one tag
here called application.
And you can see here that there's
a few different attributes defined.
We have things like our
icon that we're going
to use for the app, what the name
of our app is, the theme of our app.
And then next we have are the
activities that are used in the app.
So these were automatically
generated for us.
We have one activity here
that's called main activity.
And then here, we're just
declaring a few different things
that this activity is allowed to do.
You don't have to worry too much
about what these are right now.
We'll be adding another
one of these later.
But this basically is
a configuration file
that Android can use in
order to launch the app.
So from this configuration
file, Android can figure out
all of the different
activities your app is using.
And it needs that sort of information
for the system to work correctly
and for everything to sort
of launch the way you expect.
So we won't modify this file too much.
Let's see what else we've got.
We've already seen this main activity.
That's the same as it was last time.
In this package we have a
couple different test files.
So we might want to write some
tests for our Android application
to make sure that, let's say, when
you're doing some manipulation of data,
that the result of what
you expect it to be.
So you can automatically
write some tests here.
And there's just a couple different
packages for you to do that.
So we won't be looking
at those right now.
Next, we have this res folder.
And that's short for resource.
So the ones that we are going to
look at are first, our layout.
So recall that the
layout is where we define
what views are going
to be in each activity
and how those views are laid
out relative to each other.
So Android has this kind of
nice drag and drop editor,
if you just want to sort of drag
around buttons onto your screen
and see what the screen would look like.
But if you come down to the bottom
here, we have this tab that says text.
If you click that, then you can see
the underlying XML for these views.
In these videos, we're mostly
going to be working in XML,
but you're also welcome
to use the design view
and drag and drop just to
start prototyping your apps
and sort of see what it looks like.
So let's just quickly walk
through what's happening here.
This is a pretty simple layout.
It looks like we have this tag
here, called ConstraintLayout.
Here's that AndroidX
package we used before.
Again, this is just sort of a
set of classes and libraries
that your Android app might want to use.
So this ConstraintLayout
is just a way of laying out
views inside of each other.
And you can sort of attach
constraints, as we'll see here.
So don't to worry as much
about these two attributes.
They're just sort of
setup for Android saying
we're using this sort of
Android dialect of XML.
Next are two attributes we'll see a lot.
And this is the layout_width
and the layout_height.
And so this defines, as you'd guess,
the width and the height of this view.
So you'll see that they're both
set to a value of match_parent.
And so this means that I want
the width and height of this view
to be the same as whatever my parent is.
So basically, fill all of
the space that my parent has.
And because this is the first thing
in our app, there's no parent really,
we're going to fill the entire screen.
So this makes sense to sort of
be the root of our application,
because we want our activity to
use the entire screen of the phone.
So by saying match_parent on
both of these, we're just saying,
OK, we've got this root element,
it's the same size of the phone,
we can put other views wherever we want.
And again, then this
context just specifies
that this activity, this XML file,
applies to a class called MainActivity.
And that's the name of the class
that was automatically generated.
OK, so that's the layout.
That's not actually displaying anything.
That's just saying here's how everything
inside of me is going to be laid out.
And now we have a text view.
Remember that that text
view is just a simple way
to display text on the screen.
So you'll notice here, the layout width
and height are a little different.
Rather than saying match_parent, we
specified a value of wrap_content.
And so that basically means,
I want the width and height
to be dynamic based on my contents.
So there's a string here, we
can see it's just hello world.
And this is saying that
the size of the text view
is just big enough to contain
the string hello world.
Lastly, we have these
layout constraints.
And we can use these constraints because
we're inside of a ConstraintLayout.
So you can see that we're constraining
the bottom of this text view
to the bottom of its parent, the
left to the left of its parent.
It's kind of straightforward.
But it's basically saying, pin
all of the top, bottom, left,
and right of this view to be
the exact same as my parent.
And so the result of this
is that we're basically
centering this text view on
the screen, which you may
remember when we ran the app last time.
We're saying we just
wanted to display the text
and show just enough space for the
entire string hello world to be there.
But then there's all
that space around it,
just make it exactly centered
inside of my ConstraintLayout.
And that ConstraintLayout
is the entire screen,
so this just centers
something on the screen.
Pretty simple.
You'll also notice on the resources over
here, we have a couple other XML files.
Just to take a look at one of them,
we have this file called strings.xml.
And this is kind of nice where you can
put a bunch of your string constants
that you might want
to display in the UI.
Later down the line, if
you're writing an app that
supports multiple
languages, for example,
this can come in handy, because
you can just say, here's
a list of all my elements in English,
here's a list of everything in Spanish,
and just sort of swap them out.
But if you come back to that Android
manifest file we looked at before,
we're actually using some of these.
So you can see here that this
label attribute is saying @string.
And that's saying give me something
out of that strings.xml file.
Then it's saying /app_name, which
represents something with this name.
So all this manifest file is
doing is basically referencing
something else in this other XML file.
And so you'll see that as you're
browsing through some code,
things like, this one is referencing
something in the style.xml file.
So something in there
has a name of AppTheme.
If we open that up, sure enough,
there is our name of AppTheme.
So you can read the
Android documentation
to see a bit more what different
colors and themes and other things you
can use these resources for.
But at the end of the day,
they're all just XML sort
of following that same format, and
Android just tells you what type of XML
to write and how to configure
things to do what you want.
The last thing that we can take
a look at is our Gradle scripts.
So remember that Gradle is
the build system for Android.
So when you're writing C code, you
could specify a bunch of different flags
to the C compiler.
Gradle is basically a wrapper
around the Java compiler.
And you can use it to specify flags
and dependencies and things like that.
So if I open up this second Gradle file
here, this one that says module app,
this is what a Gradle file looks like.
It's actually written in this other
programming language called Groovy,
but you can just think about
it as a configuration file.
So here, you can see
a bunch of the stuff
that we specified when we were
creating that Android project.
So you can remember that we
set our minimum SDK version,
our target SDK version.
We created that package name.
And all Android Studio did was
generate this Gradle file based
on what you typed into that wizard.
And the section that we care about
is this dependencies section.
And this is where you're going to be
adding libraries, either from Android
itself or from third-party developers.
We're going to see an example of both.
But here, you can see we're
already using a few libraries.
We saw that we had that
AndroidX AppCompat class.
That was the base class
that our activity extended.
So here's where that came from.
We actually downloaded in the
background some library from AndroidX.
Its version was 1.1.0.
And then we could use that.
Similarly, that ConstraintLayout,
that also came from a library.
It came from this library called
androidx.constraintlayout,
happens to have a version.
And Gradle took care of downloading
those libraries, putting them somewhere
our application could use, and then
all we have to do is import them.
And that's basically it.
There's a few other files
that were generated,
but we're not too worried about those.
But that's everything that
we're going to need to use
to write our Android application.
So now, let's jump back
to our main activity
and get started writing our Android app.
So I'm just going to close out
these other files that we looked at.
So we're going to be
using a recycler view.
And that recycler view is going to be
used to display a long list of pokemon
on the screen and handle everything
from scrolling and making sure
that everything fits on the screen.
So the first thing I want to do is add
the RecyclerView to my application.
So if I come over to
developer.android.com,
you're going to find a ton
of resources for Android.
The documentation is
actually really, really good.
It's really nice.
There are lots of different
tutorials and walkthroughs
that'll sort of give you
examples of a bunch of things
you might want to do in your app.
And so here's what the documentation
for RecyclerView looks like.
So notice, it even starts
with the glossary of terms.
We're going to go through
all of this together.
But then at the end, it will list out
all of the different methods and fields
that RecyclerView has.
So if you're wondering
how to do something,
the Android documentation
is a great first stop.
OK, so let's jump back
to our application.
And the first thing we want to do is
add the RecyclerView library to our app.
So to do that, we're going
to open that Gradle file.
And then we're going to line add
a line that looks just like this.
So rather than saying
androidx.constraintlayout,
we're going to say
androidx.recyclerview.
That's sort of the package name.
Then the name of that
library is RecyclerView.
And I happen to know that the
most recent version is 1.1.0.
You can find that just by browsing
the Android documentation.
So now I get this message in Android
Studio that's the Gradle files
have changed.
Yes, they have.
I just changed them.
And so if I click this sync
button, what this is going to do
is build the project,
download any of the libraries
that I just specified from the
internet, and put them in a place
where I can use them.
So it looks like my
build succeeded, which
means we just downloaded
RecyclerView, and now we can use it.
So when writing an Android
app, I like to start
with the view to sort of understand
what it is I want my app to be doing.
Then from the view,
think about what models
I'll need to create to
[INAUDIBLE] power that view.
And then lastly, write the controller
to hook up those two things.
So let's do just that.
Let's start by looking at the view.
So let's open up our main activity.
And we know that we don't
really need a text view anymore,
because we want to replace
that with a recycler view.
So let's start typing RecyclerView.
And again, autocomplete is
really going to help me out here.
I just hit enter, and, boom, I have
the full path to that recycler view.
I didn't have to memorize that.
And then it even added in these
width and height attributes,
since they're required.
You need to specify the size
of any view that you add.
And then it also told me
what values I can put there.
So we've already looked at both of them.
There's wrap_content and match_parent.
And in this case, we want the recycler
view to fill the entire screen.
So I'm just going to
say match_parent here.
I just hit enter and
Android Studio jumped me
to the next thing, which is really nice.
So that's match_parent.
I'm going to say match_parent there.
And then if I just
type a slash, Android's
going to close that tag for me.
So now, I can get rid of this.
And I just have a single recycler
view filling up the entire screen.
Before we finish here we
want to do one more thing,
and that's to add an ID
to that recycler view.
So inside of our
controller, we're eventually
going to want to manipulate
that recycler view.
And in order to do that, we need
a way to reference this view.
And the way that Android
enables you to do that
is by giving each view a unique
identifier that you specify.
And then you can use that identifier
from your Java code and your controller
to access the object that
represents this view.
So giving something ID's is really easy.
I can just say Android: id,
autocomplete is going to help me out.
And now every ID starts with this prefix
here that, again, autocomplete told me,
which is @+id/.
Great, I'll hit enter.
And now I can type in the name of my ID.
I'm only going to have
recycler view, so we're just
going to call this RecyclerView.
And there we go.
So now I have a way for my Java
code to reference this recycler
view, which we're going to need.
So that's the list,
but we also need a way
to define what each row in
our recycler view looks like.
So to do that, we're going
to create a second layout.
And this layout is going to represent
just the row in the recycler view.
So let's come over to
the left hand side.
We're going to control click on layout,
because we want to create a file there.
Then we're going to come over here to
new, and then layout resource file.
Looks good.
So now it's just asking
me for a file name.
Let's call this pokedex_row.
And then it's also asking me what
we want the root element to be.
Before we used that
ConstraintLayout, which
allows you to constrain
things to the screen.
Here let's just use a linear layout,
which is a little bit simpler.
It's just going to layout
views right next to each other.
And a row is just
going to have one view,
so let's just use that,
because it's simple.
Nothing else here really
matters, so let's just click OK.
And there we go.
So now we've generated a second
XML file that we can use.
We're going to get rid of Gradle
for now, come down here to text,
and get the XML that was
generated And you can see here,
it's pretty much the same.
We have a linear layout.
The width and height are going to match
the parent, whatever my parent is, just
fill it.
And now inside of this layout, we
now want to create a text view.
So again, we have to specify the width
and the height of this text view.
So we're just going
to say I want it to be
the same as my parent for both of them.
And then we also want to
give this text view an ID.
So let's say my ID.
Let's just call this
pokedex_row_text_view.
Close it out.
And while we're here, let's also
give this root element an ID,
because we might need that later.
So we'll say android: id, and
this is just my pokedex_row.
And again, we want to make sure
we're not closing this tag here,
because there's something inside of it.
So this is a pretty simple layout.
It's even simpler than the last one.
We just have a linear layout
and one thing inside of that,
and that's going to be a text view.
And then later, we're
going to be using that.
So now that my layout is finished,
I'm pretty much done with the view.
So now let's think about the model.
Our pokedex is going to
be pretty simple to start.
The only data that we're
going to have is the name
of the pokemon and it's number.
So every Pokemon has a
unique number that can you
can express using an integer.
So let's now create a Java class
to represent a single pokemon.
So I'm going to come back over
here to the left hand side,
going to control click here, and I'm
going to create a new Java class.
It's name is going to be Pokemon.
No superclass, no interface, just a
regular class, nothing else to do here.
And much like before, we
have this empty class.
So let's give it a couple of properties.
Let's say we have a property called
name and a property called number.
We're going to keep these
private, because we're
going to write getters later.
Now let's create a constructor.
The constructor is going to
take a name and a number.
All we're going to do is save them.
And now let's write two getters,
just to keep these things private,
in case we want to change how
they're implemented later.
So we're going to say
public String getName().
That's just going to return name.
And then we're going to
say public int getnumber().
And that's just going to return number.
And you'll notice that
Android Studio is nice enough
to even suggest the
names of the getters,
just to really minimize
how much code I'm writing.
And so there we go.
And so you'll notice we didn't
write setters here either,
because this class is
basically a read-only class.
You might find this called a value
class somewhere in Java as well.
But there's no sort of other methods.
It's just a container
for these two data types,
so that you can have one object
encapsulate both a name and a number.
OK, so that's it for our model.
Pretty simple.
And so now the last thing we want
to do is hook up a recycler view.
So a recycler view has another class
attached to it called an adapter.
And the adapter class
basically defines what
data is going to be displayed
in the recycler view
and then how that data
should appear on the screen.
So I know that I want
to create a new class.
So I'm going to come over here
to the left, say new Java class,
and we're going to call
this PokedexAdapter.
Again, no superclass or interface,
so same as what we're used to.
So this is the class that's
going to represent all
of the data inside of my recycler view.
The base class for this class
is going to be something
that's given to us by RecyclerView.
So I'm going to say extends
RecyclerView, nicely automatically
imported it for me, dot adapter.
And so this is a class that's
given to me from RecyclerView,
so it has a bunch of
methods inside of it.
And it also has a few methods that
it requires me to implement myself.
And this class is also a generic class.
And it takes, as its sort of type,
something called a view holder.
Now a view holder is what's going
to, as it sounds like, hold a view.
And it's going to allow me to
manipulate what's on the screen.
So we're going to say, here's a
view that's displayed on the screen.
I'm going to define a little
object to hold onto that view.
And from there I can modify some of
those layout elements I just described.
So we're going to write
this class, as well.
We haven't created it
yet, but we're going
to call it
PokedexAdapter.PokedexViewHolder.
So let's go ahead and
define that right now.
We're going to make this private,
because nothing outside of the adapter
is actually going to use this
class, so no need to make it public.
So we're going to say private.
We'll make it a static
class here, so we can
say PokedexAdapter.PokedexViewHolder.
And now we're going to
call it PokdexViewHolder.
And now we're just going to extend
it a RecyclerView.ViewHolder.
And so now we've defined this valid
class that we can use and pass in.
So let's add a
constructor to this class.
Let's say-- forgot the word class.
That's why the compiler
is not happy with me.
So now let's say PokedexViewHolder.
And it's going to take as
its parameter one thing.
And that's a view.
And you'll see here
that this is basically
the most generic view possible.
Basically, all of the Android views are
going to subclass from this base view.
So it's just sort of
the most generic thing.
And so now this ViewHolder, we now want
to create fields for those two things
we added IDs to.
If we jump back to that Pokedex
view, the view we want to hold
is one of these.
And it has two things.
It has a layout we care about.
And it has a text view
that we care about.
So let's go ahead and add
fields to this view holder class
to represent those two things.
So we're going to have a linear layout.
And let's call that our containerView.
And it's also going to have a text view.
And let's just call that our textView.
So now we want to access those
views from this base view.
And remember, the reason
we gave those things IDs
was so that we could do just this.
We can go from our Java code, grab
the object representing a text
view or linear layout, and get it back.
So the way to do that is to
say containerView = view.
That's the view that was passed in.
Then there's this method findViewById.
And you'll notice that it
looks like it takes an integer,
but that's kind of weird.
We gave things strings.
Something that's
happening under the hood
is that Android Studio and Gradle are
automatically generating unique IDs
for all of those strings.
And they put them inside
of this class called R.
And the R stands for resource.
And it has a bunch of
methods that you can use
to access these different resources.
The resource we care about is id.
And if I say R.id, you can notice
that here are the IDs that I created.
Autocomplete is really going to
help you here, in case you forget.
So if I just say R.id.pokedex_row,
this represents a unique ID.
It's an integer that Android generated
for me that represents this container.
So I can get the text view
in the exact same way.
I can say textView =
view.findViewById(R.id.pokedex row text
view).
And it's automatically also going
to give me back the right type,
so I don't have to
worry about any of that.
OK, so that's it for
our view holder for now.
All we've done is we've
taken this view that's
passed in from the recycler view.
And we've converted into something
that we can actually use.
So now, the last thing to do is
to implement a few methods that
are defined on recycler view adapter.
The first method that we're going to
override from our recycler view adapter
is called onCreateViewHolder.
I can just start typing
onCreate and autocomplete is
going to do the work for me.
So this is a method that's called when I
want to create a new view holder, which
makes sense.
So the first thing we want
to do is get our layout file.
So we want to go from
a layout to a view.
And so the way to do that is we're going
to create a new variable, called View.
And this is going to use this
Android class, called LayoutInflator.
Let autocomplete take care of that.
And then we're going to call a
method on LayoutInflator called from.
And this is basically saying, where
do I want to get my layout from.
There's this argument that's
passed in, called parent.
We're just going to use that.
Don't worry too much
about what that one means.
What actually matters is
this thing called inflate.
So inflate is going to say I want to
go from some XML file to a Java view.
And so we need to pass in
what file we want to inflate.
So we want to inflate
our R.layout.pokdex_row.
And again, just like we had
that R.id generated for us,
we also have this
R.layout generated for us,
which again, has a bunch
of these unique IDs
that we can use in a
lot of these methods.
Now from the documentation, this method
also takes a couple of the parameters.
One is a parent.
That's passed in for me.
And then last, we can
just pass in false.
This is just some different
behaviors you might want to do.
We're not really worried about
that, so we can just say false.
And so now what we've done
is we've converted this XML
file into a Java object in memory.
So this is our view
that we want to hold.
And you'll notice that the return type
of this method is a PokdexViewHolder.
So let's just return a
new PokedexViewHolder.
And we're going to give
it that view to hold.
That's the first method
that we need to implement.
The second method we want to
implement is called onBindViewHolder.
Now this is the method that's going
to be called whenever a view scrolls
into screen and we say,
we need to set the value
or set the values inside of this row.
So here is where we're going to want to
actually set the different properties
of the view that we've created.
But you'll notice that we
don't yet have any data.
So let's do that.
Let's just hard code a
few Pokemon to start.
So to do that I'm going
to create a new list.
The type of this list is
going to be our pokemon class.
And we'll just call it pokemon.
Android Studio trying
to be helpful here,
but it's not as well versed in
the pokemon universe as we are.
And just as we did before, we're
going to use that nice Arrays.asList
utility to create some pokemon.
So now, inside of this list,
let's just create a few.
So there's first Pokemon.
Its name is Bulbasaur.
Its number is 1.
Next-- whoops.
Next one, the name is
Ivysaur, number is 2.
Make sure that's a
comma, not a semicolon.
And lastly, we have name of Venusaur.
His number is 3.
So that's a really simple model for now.
It's just hard coded.
We're later going to
dynamically generate this list,
but let's just start by hard coding it.
So now in onBindViewHolder, we want
to go from this model to our view.
And remember, that's quintessentially
what a controller is doing,
is going from a model to a view.
So let's grab an element
out of this array.
So let's say our current
pokemon is using this list.
And which one do we want to get?
Well, it looks like this method has
this other parameter called position.
And that's going to represent
what row we're currently in.
So we just want to get the
pokemon at that position.
So now, we want to just go ahead
and set the values for this row.
So first, we notice that when we
came up to here to the view holder,
we made these two things private.
Again, that's sort of convention,
but just for speed, let's just
make these public for now.
And while I'm here, I also notice
we forgot to call super on this,
so let's make sure we do that.
Again, you want to make sure
that you're calling super, just
in case those super classes
are doing something important.
In this case, it probably is,
so let's go ahead and do that.
So the only thing we need to do to
this row right now is to set its text.
So let's go ahead and do that.
So we have an instance of a view holder.
We just made textView public.
And so now we can call
this method setText.
You'll notice that there is a
version that takes a string.
So we can just say current.getName.
And this is saying I want to
take that name object, set
that to be the text of the row.
And that's it.
This is void method.
We don't have to do anything
else, because we've just
modified this view holder.
Now the last method we have
to define on our adapter
is how many rows to display.
So if I start typing item, there's
this method called itemCount.
And now we need to return
the size of our list.
Well, we know what the
size of our list is.
It's just however big this array is.
So we can just return pokemon.size.
And that's it.
Now we have a fully working
recycler view adapter.
So the last thing to do is
to actually use this adapter.
So to do that, I'm going to
come back to my main activity,
and I'm going to add a few more
fields that a recycler view needs.
So we're back in main activity.
So let's add a few fields.
The first is our recycler view.
We'll just call that RecyclerView.
Now we need a couple other things.
One is our adapter.
So we know that we've called
that our pokedex view adapter,
but we'll just use the
generic version here.
We'll call that adapter.
And lastly, we just need
something called a layout manager.
And we'll just call that layout manager.
So those are the three fields
that we're going to need
to instantiate our recycler view.
And so now let's instantiate them.
So our recycler view is going to
be this findViewById thing again.
So remember, now we're in our
main activity layout file.
In there, recall that we created
an ID called RecyclerView.
So really easy way to get that.
And so now we need to
set those adapters.
So we can say my adapter is
going to be a new PokedexAdapter.
We didn't specify any
parameters in the constructor.
That's fine.
Next, we want to create
that new layout manager.
Remember, we used a linear layout, so
we can just say new LinearLayoutManager.
And then it just needs a
reference to the activity.
So there we go.
Now lastly, we want to
connect those things.
So we want to say RecyclerView.
We want to set the
adapter to be my adapter.
And we want to set our layout
manager to be that layout manager.
And so now what we've done is we've
instantiated that recycler view.
We've set the adapter for that recycler
view to be that adapter that we wrote.
And so now it knows
what data to display.
So now let's go ahead and run
this project and see what happens.
OK, so it looks like
we've got an error here.
So let's check out what that error is.
I can just double quick here.
And it looks like PokedexViewHolder
holder has private access.
So, whoops, looks like we mistakenly
said public here-- or private.
If we just change this to public,
we'll notice that that error goes away.
And this makes sense,
because we actually
are using this class
outside of the class,
because we're using it
in this declaration.
So private didn't actually make sense.
So now let's try running it again.
So it looks like it
installed successfully.
So let's pull up our app.
It looks like we're close.
It looks like we have a list with
Bulbasaur, Ivysaur, and Venusaur,
but it's kind of weird, because each
one only fits sort of, like, one
on the screen at once.
So let's go back to our layout
and see why that might be.
Ah, so it looks like we've
set the heights to instead
be matching the entire parent.
So instead, we want to just
set this to wrap_content,
so that the height of each row is just
simply enough space to fit that row.
Instead we're saying the
height is the entire screen.
We just want to make the row just big
enough to fit everything inside of it.
So that's fixed.
Let's run it again.
And this time you got something a
little bit more of what we wanted.
So now we have each row displayed in
our pokedex and they're on the screen.
So the next thing we want to
do is create a new activity.
And this activity is going to appear
when one of these rows is selected.
So let's jump back to Android Studio.
Over here on the left hand side, let's
go to new, down here to activity,
and then we're just going to pick an
empty activity again, because we're
going to be writing the layout ourself.
So our activity name, let's
call it PokemonActivity.
And you'll notice here that
we have this checkmark that
enables us to generate a layout file.
So let's leave that checked so that
Android Studio rights a little bit
of that boilerplate for us.
Our layout name, we can keep
the same, just activity_pokemon.
Don't need to worry about anything
else here, so let's click finish.
And the file that's generated here is
just like the other files we've seen,
so nothing crazy there.
And you can see that we have
a new layout file over here
to the left called activity_pokemon.
So let's close out a
few of these other tabs.
And just like we did before, let's
start by writing our layout file.
So rather than using
a ConstraintLayout, we
can just use a linear layout,
since all we're going to do
is display a couple of text views
stacked on top of each other.
So let's change this
to be a linear layout.
That's all we need there.
We want to make sure that the height
and width are both match_parent,
so it can fill the entire screen.
This context that was generated for us,
we'd just have that be PokemonActivity.
And then let's make sure
the closing tag matches.
And now let's add a
couple of text views.
Let's say one going to be
wrap_content, so it's just big enough.
Let's give this an ID,
because we'll need it.
And we'll give that an
idea of pokemon_name.
We can set a couple other
attributes while we're here.
For example, we might want
to set the text alignment.
So we want to center
this text on the screen,
so let's give it a text
alignment of center.
And then we might also
want to set the size.
So if I just start typing
size, I can see textSize.
And we're going to give
this a size of 18 dp.
So dp here is a device or
density independent pixel.
And this basically is a way of using
pixels to specify the size of things.
But on all these different phones
with different densities of pixels,
that can kind of get
confusing, and so this is just
kind of a way to normalize
across all of that.
So we want to just say
this is a size of 18.
That's pretty big, but not too big.
And now that's one, so let's
just add one other text view.
This is going to be displayed below it.
This time, let's say
it's a pokemon_number.
Still want to center it.
Yeah, let's give it a size.
Let's make it a little smaller.
And let's also do something to
sort of space things out a bit,
so let's add some padding.
Let's say we have android: paddingTop.
Let's just give this 10
pixels of space there.
And then maybe 5 pixels of space here.
OK, so that's everything
we need for the text views.
So the last thing we
want to do is specify
that we want our views to be
stacked on top of each other,
not next to each other.
So to do that, we're just going to
add one more attribute to our layout.
We're going to say the orientation
of this layout is vertical,
rather than horizontal.
And so that will nicely give us
text views on top of each other.
OK, So now let's return
to that Java activity.
So what we want to do when
this activity is created
is take some text that's passed
into us and display it on the view.
So let's do what we did last
time and create a few fields
that represent our text views.
So we have a text view
representing our name.
And we have a text view
representing our number.
And so now, inside of onCreate is
where we want to set those values.
So to get those values,
remember that we're
going to use the special
object called an intent.
An intent is how we're going to pass
data from one activity to the other.
So let's write the second half first.
To get the intent that
started this activity,
you just have to call getIntent.
And this is a method that's defined
somewhere in AppCompat activity.
And so we can just use it.
So we can say getIntent
and getStringExtra.
And so this is saying I want to
get some of the extra data that
was passed along from this intent.
And I want to get it as a string.
And so let's say I want
the string called name.
And I'm going to store that
in a variable called name.
Similarly, let's grab the number, so
we'll say int number is getIntent.
And rather than a string extra,
we want to get an int extra.
Say that's the number.
And then with int, we also have
to specify some default value,
in case it's not passed
in, so we'll just say 0,
but we're always going to pass this
in, so we're not that worried about it.
Lastly, let's set the
contents of those text views.
So let's say nameTextView.
Let's use that findViewById again.
But here we're used to this R.id
dot, we called it, pokemon_name.
And our numberTextView, we
called that pokemon_number.
And so last, we can just call
that same set text method,
the same one that we've called before.
And we'll say
nameTextView.setText(name).
And then numberTextView.setText.
And then we also, right
now, we have an int.
And we want to create a string.
So we can just say
Integer.toString, pass in that int,
and so this will just nicely
convert an int to a string.
And so that's it for this activity.
It's pretty simple.
We're not doing too much.
We're just taking some data
that we received from our intent
and we're displaying it.
So now let's set the first
half of this interaction,
which is how we pass data from
the first activity to the second.
So to do that, I'm going to jump
back into my pokedex adapter.
By the way, to jump around quickly in
Android Studio, if you hit shift shift,
you can get this nice
little search field
where you can search for file names
or classes or really whatever.
So that's kind of a
nice way to jump around.
So let's think about how we can
pass along this pokemon data.
So we know that we have the
Pokemon that we want to pass inside
of this onBindViewHolder method.
And really, it doesn't look like
anywhere else in this class,
I have access to that.
The view holder takes in a view.
All these other methods
don't have any position.
So we know that we have to add it here.
And so we want some way to pass
along this object to our view holder.
And luckily, view holder has a
nice method that's built in here.
I can say, I have my containerView.
And I want to call
something called setTag.
And a tag is basically just some
object that's associated with the view.
A tag can be anything, which is nice,
because we have this pokemon object
that we want to send along.
So let's just set that as the tag.
So now our view holder has
access to its current pokemon.
So now that we have access to the
current pokemon from the view holder,
let's add an event handler that can
be executed when the row is tapped.
To do that, we're going to say
containerView.setOnClickListener.
And this is going to
take one argument that's
going to be an instance of a class.
But we're only going to
use this instance once,
so we can use this nice Java syntax.
We can say [INAUDIBLE]
View.onClickListener.
And we're going to do here is write in
line, we're going to define the class,
and then instantiate it.
So it looks like this
class just has one method.
It's called onClick.
And it's the view that was clicked.
So let's first get that pokemon.
So we can say Pokemon current is
equal to my containerView.getTag.
But you'll notice here
from the autocomplete
that getTag returns an object.
And so we just need to
cast that to a pokemon.
We know that when we called setTag, we
set that to be an instance of pokemon,
so we can safely cast
without a problem here.
So next we want to
create an intent object.
So let's go ahead and do that
and say intent is a new Intent.
And now this is going to
take a couple of arguments.
The first argument is just that
context object we saw before.
Don't worry too much about that.
You can just say getContext.
And then the second
argument it's going to take
is what class we want to instantiate.
So we want to instantiate
our new pokemon activity.
So we're going to say
PokemonActivity.class.
Now that we have our intent,
we want to set those extras,
since we know that we
were getting them before.
So we're going to say intent.putExtra.
We want to say our name
is our current.getName.
And then we want to say
our number is getNumber.
So that's it for creating the intent.
It's pretty simple.
It's just saying here's an
activity I want to go to
and here's some data that I want
to pass along to that activity.
And so now the last thing
to do is just to call
start an activity with that intent.
So I can say getContext().startActivity
and pass along my intent.
So now, let's go ahead
and try running this.
Looks like my install worked, so
let's jump to the Android emulator.
Here's our recycler view as before.
Now let's tap on Bulbasaur here.
And there we go.
It looks like we're now displaying our
second activity with that information.
Just to be sure, let's
try tapping on Venusaur.
And it looks like we're successfully
passing data back and forth.
But now, when we look at this
recycler view, it's kind of smushed
and doesn't really look like a
lot of Android applications do.
When you start tapping
on something, there's
no indication that anything happened.
So let's make this recycler
view look a little bit nicer.
So to do that, let's jump back to
the activity for our recycler view.
So this is our main activity.
Remember, we added this recycler
view with a row of pokemon_row.
So we're back here.
So the first thing we want to do is add
a little bit of padding to each row.
So just like we did before, let's
say, it has a padding of 10 pixels.
And so this will automatically add
padding to the top, bottom, left
and right, so that's nice.
We also want to indicate to
the user that it's clickable.
So we're going to set
clickable to true and we're
going to set focusable to true.
So those are just sort
of ways to indicate
that you can actually tap on this row.
They're not just
statically presenting data.
Now the last attribute I want
to add is that nice effect
you see on Android when
you tap a row and there's
that sort of ripple
effect on the background.
We can actually get that for free
without writing a lot of animation
ourself.
We can just say android: foreground.
And then we're going to
use this interesting syntax
to access some of those built-ins.
We're going to say android: attr,
which is short for attribute.
And so now, if I just start typing,
I can see a bunch of different things
I can access.
The one that I want is called
selectable item background.
And this just sort of
adds that nice animation
to the row when you tap on it.
So I also noticed when I ran it,
that the text on that second activity
wasn't centered.
So let's take a look
at why that might be.
If we jump over here to
text, you'll notice here
that we set both the
width and the height
to wrap_content, which
means that the width is only
going to be big enough to fit the text.
And because of that, we haven't
actually centered anything.
We're basically saying it's
centered, but it's only with--
you know, it's only a
third of the screen,
so it's not actually
centered within the screen.
So to do that, I instead want
to set match_parent here.
And this says that we want the
container for the text view
to fill the whole screen
and then center within that.
So that means it's actually going
to be centered on the screen.
So those changes let's
try running it again.
My install worked, so let's open it up.
This looks a bit nicer.
So there's my padding coming into play.
It's not squished anymore.
Now let's try selecting a row.
You can see I had that
nice ripple effect.
I didn't have to do
anything to get that.
And now my text is actually centered.
So let's add one more finishing
touch to this pokedex activity
before we're done.
Rather than displaying the
number 2, let's display it
as an actual pokedex would, where
the number is padded with zeros,
so it's always a three digit number.
So to do that I'm going to come
back to my PokemonActivity.
Rather than just setting the text
to this Integer.toString(number),
I'm going to use a method called
string.format that's basically
equivalent to printf() in C.
So I'm going to say string.format.
And just like printf(), this
is going to take two arguments.
The first one is my format string.
So remember that in order
to pad zeros to something,
I can just say %03d and that'll say,
give me an integer that's padded with--
it has always three digits.
It's padded with zeros if not.
And then my other argument
is just the integer
I want to format, which is number.
So same exact print syntax as printf.
So if I add that and run my app one
last time, we've installed successfully.
If I tap on the row, I'm
now getting everything
formatted the way I wanted it to be.
So that's it for our simple pokedex app.
Next, we're going to take a look at
how to dynamically add information
to this app, rather than hard coding it.
