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.