Anda di halaman 1dari 109

Android Tutorial for Beginners: Part 1

Darryl Bayliss on November 10, 2014

Update note: This tutorial was updated for the latest version of Android Studio by Darryl
Bayliss. Original tutorial by Matt Luedke.
But when does the Android version come out?
The first blog comment after any iOS app gets announced.
Clearly theres a demand for Android app development, and its turning the platform with the
lovable green mascot into more and more of a strong first choice rather than just a secondary
option to iOS.

With over one billion devices activated, Android is an exciting space to make apps to help you
communicate, organize, educate, entertain or anything else youre passionate about.
If thats not enough, here are a few more reasons to learn Android:

Youll be plugged into the open source platform with (at the time of press) the largest
market share of smart devices worldwide.

Androids policies on device provisioning and app submission are more open than
Apples, meaning that once you complete your first appas youll do in this tutorial
you and your friends can enjoy it on your devices right away!

If you have experience developing for iOS, you can become well-versed in the ways that
the two platforms coincide and differ (well discuss a few in this tutorial) and what you
like about each. Then youll have more tools at your disposal for your next mobile
project.

Its not just the iPhone anymore. There are so many smartphones, tablets, glasses, and
watches out there, coming from so many manufacturers, and theyre all trying to jump
into the game. You dont have to be any sort of market analyst to know that there are a
few important platforms and Android is one of them.

So if youve been intent on, thinking about, or simply playing with the idea of learning
Android Make Your First Android App is the tutorial series for you!

There arent any prerequisites to start. Youll learn how to set up all the tools you need to become
an Android developer-in-training. Then youll put together your own full-fledged Android app
from scratch! This app will, when completed, help you get details about a book youre interested
in using online search sources.
By the end of Part Three of this series, your app will include useful features like:

Saving app data locally on the phone.

Loading and interacting with a dynamic list of data.

Accessing an online data source.

Sharing links through social networks.

Android, and several popular frameworks for it, make all of these features really simple to
implement. Why not start learning this easy and powerful platform for yourself, today?

Getting Started
How does Android development go down? First, the zoomed-out basics:

Youll write your programmingwhat you want your app to doin Java files and design
your layoutshow you want your app to lookin XML files.

Once your app is ready, youll use a build tool to compile all the project files and package
them together into a .apk file that you can run on Android devices and/or submit to
Google Play.

All of the files you used to put your app together are managed by an Integrated
Development Environment (IDE). The IDE is the program you will open to edit your
code files and to manage your projects.

The standard IDE for Android used to be Eclipse, but this is now being replaced by
Googles own Android Studio.

If you zoom in (metaphorically), youll find more in-depth processes going on behind the scenes
during all of the above steps. For example, advanced users will want to investigate the role of the
Dalvik Virtual Machine and its new replacement, ART.
But for now, lets move on. Heres what youre going to accomplish in this part of the tutorial:
1. Download and install Android Studio.
2. Set up testing on devices and emulators.
3. Create a simple Hello World! Android app that prints to your devices screen.
4. Make small edits to the app so it can congratulate you by name.
In the second part of this tutorial, youll make an app that records a message you type, adds it to
a list, saves it in memory and shares it with friends. Along the way, youll learn how to add and

configure various UI elements such as ImageViews, Buttons, ListViews, and EditText


controls.
Finally, the third part will cover how to make an app to search an online database of books,
display and share the cover images of the search results, and navigate between the different
screens of your new app!

Installing Android Studio


Its really tempting to jump in, start writing code right away and figure out the various Android
features as quickly as possible. And you will get there soon! But one of the most important parts
of getting started with a new platform is setting up your environment.
Especially for beginners, its important to take your time here and follow each step methodically.
Even if you follow the steps perfectly, you may have to troubleshoot some small issue,
depending on your system configuration or product versions.
Its important to not let any roadblocks prevent you from your ultimate goal of learning Android.
Even seasoned professionals have been known to have some trouble with the new Android
Studio.
Note: Just as much as youre training in programming syntax and frameworks, its important to
train yourself to have a successful programming mindset one that wont accept file X not
found as a final answer. 90% of this mindset is simply training yourself to keep trying till you
find a solution.
With all of this in mind, lets quickly check that you have the Java Development Kit (JDK)
installed. You might already, even if you dont know for sure.
To check, youll use the Terminal. If youre unfamiliar with the Terminal, you may want to read
a good introductory tutorial about working with the Terminal.
In a nutshell, your Terminal is like looking under your cars hood. Its how you really get to
know the machine face-to-face, without any complex graphical interface in the middle. You can
find the Terminal app quite easily on a Mac using Spotlight. Search for terminal and click the top
hit to run Terminal.

Once you have the Terminal open, type in java -version. You should see some output that
mentions a version number, like below.

If you dont have the JDK installed, your Terminal will tell you command not found. If thats
the case, you should download the JDK from Oracle.
When ready, head over to the Android Studio page and click the big green button to download
the correct version for your Operating System.

Google is constantly updating this page, so the version you see may be newer than the screenshot
above. Once you have clicked the button youll be asked to agree to the Terms and Conditions:

After reading these carefully (as you always do) accept the Terms and Conditions and click the
blue button underneath titled Download Android Studio. Your download will finally begin. It
may take a few minutes but once finished you can install Android Studio similar to any other
program.
The download page will helpfully redirect to a webpage that contains installation instructions for
OSX, Windows and Linux Operating Systems. If for some reason the instructions dont appear
then you can also view them here.
Now that youve installed Studio, lets fire it up! Launch Android Studio.

Once Android Studio has finished loading, youll be greeted with the Setup Wizard the first time
Studio loads.

Click Next to move to the next screen. This screen will ask what type of setup you would like.
Make sure Standard is checked and click Next again to move to the next screen to accept some
licenses for components that will be installed on your computer.

Accept these and click Next one last time to begin downloading the extra components you will
need.

After a few minutes you will have everything you need to begin building fantastic Android Apps
and will move to the welcome screen.

Even though you just downloaded Android Studio, you might not actually have the latest version.
Right away, you need to check to see if any updates are available and if necessary, follow any
instructions to get the latest version. You can check whether any updates are available by
clicking check for updates at the bottom of the welcome screen.
If an update is available you will have a window like this appear:

When you see this screen. Always choose Update and Restart. In some cases, you may need to
download the full installer in that case you will see a Download button that will take you to
instructions for installing.

Great! As all programmers in the movies say when they are successfully greeted with a new
interface: Were in!

Optional/Advanced: Moving from Eclipse


You can skip to the next section if you are new to Android development.
Android Studio is a new IDE that Google is constantly updating. If you are already involved in
Android development, you are probably using Eclipse. For the transition, the Android team has
put together a helpful guide on how to move from Eclipse to Studio.
The process can still be a little bumpy, even for advanced users, so the best advice I can offer on
that front is to make sure that your version of Gradle is up-to-date, as well as your versions of the
Android Platform Tools and Studio itself.
Its also important to check the PATH of your Android software development kit (SDK) when
switching to Studio. Otherwise, Studio may not be able to find the right Android SDK or Build
Tools!

The Android SDK Manager


Each version of Android has its own SDK you can use to build apps that can run on. As part of
the Setup Wizard you will already have the latest SDK available to you, however its useful to
know how to install additional SDKs if you need to work with older devices that do not run the
latest version of Android.
SDKs allow you to create AVDs (Android Virtual Devices) to test your Apps on, customized to
your personal configuration. Want to see how your Android App looks on a TV sized screen? If
you have a screen big enough you can find out. More on AVDs later.
Lets get to it. From the Android Studio welcome screen, click Configure.

The menu will slide across and present a new menu with various options. The option you want is
the SDK Manager. This is the go to place if you need to download a specific version of Android
to develop or test your app on. It also contains other useful things such as API documentation,
version specific code samples and even previews of software kits that interact with Android such
as Android Wear and Google Glass.
For now lets focus on downloading a version of the Android SDK. Click the SDK Manager
option, a new window will present itself to you with checkboxes, folders and statuses across the
page.

Lets make some sense of this. Each folder is a directory of tools, software and documentation.
The majority of directories are specific to an SDK version of Android but there are some that
cater to multiple versions. The first folder for example, entitled Tools, is a folder that contains
components that are designed to assist in the development of Android and work across multiple
SDKs.
The Android 5.0 (API 21) directory on the other hand holds everything specific to that version of
the Android SDK. Including sample code for new features within the SDK, API documentation
and system images you can use to simulate a certain mobile architecture using an AVD.
If you dont understand what all this means then dont worry, just think of each folder as a place
where each version of Android and their tools live happily. From the latest preview version right
down to the original Android Beta (API 2).
You should already have the latest version of the Android SDK Tools, Android SDK Platformtools and Android SDK Build-tools downloaded from the tools directory. If an update for any of
these tools is available then the checkbox next to the tool will automatically be ticked, alongside
a polite message in the Status column of the window telling you what the latest version is.
For now lets download the previous version of Android, that being Android 4.4.2 (API 19).
Click the tick box next to the folder icon for Android 4.4.2, this will select everything within that
directory for download. You can always come back to the SDK Manager to delete anything you
dont use.
Important: Its alway worth opening the SDK Manager every time you start Android Studio to
see if there is any updates to any tools or SDKs you have installed. This ensures you get access
to the latest features in your alongside any fixes for nasty bugs.
Your SDK Manager window should look something like this:

Click Install x packages (x being the amount of packages checked for download) on the bottom
right of the SDK Manager. A new window will appear with a drop down list of the packages you
wish to install, simply click the root of the drop down list and then click the Accept License radio
button in the bottom right.
You may need to do this for multiple licenses depending on what packages you download.

Finally, click the install button at the very bottom right of the window to begin your download.

The window will disappear and the SDK Manager will begin to download and install your
selected items. Go grab a drink and take in what youve just done whilst the SDK Manager is
ticking away. This will become a regular task that you need to get accustomed to so you can
quickly acquire and update the various SDKs you want to work with.
Once the SDK Manager has finished downloading and installing your items you can move onto
creating your first Android App!

Creating OMG Android


Its time. Lets make your first project.
Youll start simple. Many first programs are called Hello World. Lets follow that tradition and
then make a few small edits so that the app uses your name to greet you. By the end, youll be
able to load your new app onto a device and show it to your friends!
Android Studio has a nice little step-by-step tool to help you make your project. Click Start a
new Android Studio Project from the Welcome to Android Studio screen:

Note: If you currently have an Android Studio project open and the Welcome screen isnt
showing, select File\New Project from the menu to create a new project.
Studio will present you with your first project creation screen:

Enter OMG Android in Application name as shown above. Feel free to put your own name in the
Company Domain textfield. As you type, youll notice the Package Name will automatically
change to create a reverse domain style name based on your Application name and Company
Domain.
The Package Name is used to uniquely identify your app amongst other apps, that way any work
an Android device has to be perform on behalf of the app always knows its source and cant get
confused between two apps. iOS developers will recognize this concept as being similar to the
Bundle Identifier.
You can set the Project location to any location on your hard drive you do not need to follow
the screenshot for that one :]
Click Next at the bottom of the window to progress to the next part of the project setup.

The next screen is where you select device types and operating systems to target. Want an App to
focus on just Phone and Tablet? Not a problem! How about an App for TV and Google Glass?
Thats great too. For now though you just want an App that works on an Android Phone. This
option is selected as the default, alongside the default Minimum SDK.
The Minimum SDK drop down menu sets the minimum version of Android needed to run your
app. Selecting this value for your own projects is a matter of balancing the SDK capabilities you
want and the devices you want to support.
For your first app, youll use the default API 16, which is Android 4.1 (Jelly Bean). Every app
will have different requirements and you may want to choose something else, depending on the
situation.
If you really want to get into the details of what Minimum SDK version is best for your App then
Android Studio can help you out. As you change the Minimum SDK in the drop down menu, the
percentage in the text underneath reflects what percentage of devices currently run that version
of Android.

If you are more about features than numbers, Android Studio has got your back too. Click the
highlighted Help me choose underneath the drop down list to display a useful new window.

What you are looking at is a bar chart, split by the amounts of devices running a specific version
of Android. Click on any part of the bar and the text to the right will change, telling you the most
significant features of the Android Version that part of the bar represents. Useful if you need a
quick overview of what each version of Android provides for your App.

Take note of the Cumulative Distribution values on the right of the bar. This represents the
percentage of devices supporting that particular version of Android which includes backwards
compatibility. As you descend down the bar, the version of Android increases and you gain more
features that your App can make use of. The downside to this is the amount of devices that can
actually run your App is reduced.
Picking what Minimum SDK your App will require is a crucial choice. It will influence what
features you have available to you in your project while also influencing how many Android
users can run your App. Choose wisely!
For more information on API versions and their use, check out the Android Dashboards, which
are updated every few days.

Getting back to the new project window, click Next in the bottom right to pick more options for
your project.

This screen lets you choose a default Activity for your app. Think of an Activity as a window
within your App that displays content the user can interact with not unlike a View Controller in
iOS. An activity can take up the entire screen or it could be a simple pop-up.
Available activities on this template range from a blank activity with an Action Bar right up to an
Activity with a MapView embedded. You will be making a lot of activities, so its good to get
accustomed with them.
Select the Blank Activity option and click Next.

If you have made it this far then well done, you are at the final screen before you dig into some
actual coding. To speed this part up a little bit you will use the pre-populated default values, but
what is actually done with these values?

Activity Name. This will give your Activity a name to refer to in code. Once the project
setup is complete Android Studio will create a .java class and use the contents of this
textfield to give the class a name. This is the name you will use to refer to your Activity
inside your code.
Note: What its actually doing is making a subclass of Activity. Those familiar with
object-oriented programming will know what this is, but for newcomers, this basically
means that your MainActivity is going to be a customized version of Activity that acts
just like the default one, handling things like its lifecycle and the user interface display.

Layout Name. Youre going to define your Activity in Java, but the layout of everything
it will show to the user is defined in a special sort of Android XML. You will learn how
to read and edit those files shortly.

Click Finish. Android Studio takes this as its cue to go do a bunch of behind-the-scenes
operations and create your project. As it shoots out some descriptions of what its doing from
time to time, you may notice it say something like the following:

You see your project name, which is familiar. But then there is this Gradle word, and then a
mention of Maven in the URL. The benefit of having a modern IDE like Android Studio is that it
handles a lot for you. But as youre just beginning to learn how to use the software, its good to
know, in general, what its doing for you.

Gradle is a new build tool that is easy to use, but it also contains a lot of advanced options
if you investigate it further. It takes your Java code and XML layouts, and then uses the
latest Android build tools to create the app package file, known as an APK file. You can
customize your configurations to have development or production versions of the app that
behave differently, or add dependencies for third-party libraries.

Maven is another project build tool, and it can also refer to the Maven Central repository
of java libraries. It is absurdly easy to use Gradle and Maven Central in concert with
Android Studio to incorporate all sorts of functionality from the Android development
community. Those with an iOS background will know how cool this sort of thing can be
from using the CocoaPods tool. Youll learn more about Maven in Part Three of the
tutorial.

After a brief moment, Android Studio will finish building your project. The project is pretty
empty, of course, but it still has everything it needs already set up so that it can be launched on
an Android device or emulator. You will be dropped off in this spot:

Android Studio will contain three windows. To the left you have your project folder structure, the
middle contains a preview of your layout on a Nexus 5 device and finally the right shows your
layout hierarchy as well as attributes if you have a part of your layout hierarchy selected. Before
you get into any programming, lets talk about how youre going to get this app running. Its time
to say Hello world!

Running on an Emulator or Device


All right: Youve got Android Studio and youve created an app. So how do you run it?
If you have a physical Android device available, youll learn how to use that soon. But for those
without one, you also have the choice to run your App on an emulator.
Android Studio comes free with the ability to set up a software-based Android device on your
computer and run apps on it, browse websites, debug and everything you would expect. This
capability is known as the Android Emulator.
You can set up multiple emulators and set the screen size and platform version for each one to
whatever you like. This is great, as with the diversity of the Android platform, youd otherwise
need a large amount of devices for testing.

If you ran through the setup wizard earlier using the standard installation then you will already
have an emulator setup and ready for you to use. Making use of some useful software developed
by Intel to ensure your emulator runs quickly for your testing needs.
Up until recently, your computer would have to emulate everything an Android device would try
to do. Everything down to its hardware which runs using an ARM based processor. Most
computers these days make use of x86 based processors, which means your computer would be
doing computationally intense tasks that take a significant amount of time just to test your App.
You still have the option to do this if you want to create an emulator that is as close to an actual
device as you can, but be aware that the initial load times have put off many an Android
Developer using the emulator all together.
All of that being saidlets set up an emulator anyway, because youre going to need to know
how!
Click AVD Manager. Its the button in the toolbar that has an Android popping its head up next
to a device with a purple display.

As you will see. Android Studio has already created an AVD for you to use. Youll see a few
details about it, notably what type of emulator it is, what API it is using and what CPU
instruction set it uses.

Lets run through creating a new AVD. Click Create Virtual Device in the bottom left to begin
configuring a new virtual device.

The first decision you need to make is what type of device you want to emulate. The Category
list to the left shows all the types of device you can emulate. Clicking each option shows you
what type of devices are available to you in that category. For now you just want to emulate a
phone sized device but if you wanted to emulate an Android Wear watch or an Android TV then
you have options to do so here.
Select Nexus S in the list of devices available to you from the phone category and click Next.

Your next decision is to decide what version of Android you want your virtual device to run. You
will already have one or two available to you thanks to the setup wizard, so lets use one of them.
Select Lollipop and make sure the one selected has the value x86 in the ABI column. We want the
emulator to be running as fast as possible on our x86 computers. :)

Click Next once this is done to move to the final screen. The last screen is simply a confirmation
of your previous choices with the option to configure some other properties of your device such
as device name, startup orientation, and RAM size. For now leave these set as their defaults and
click Finish

Congratulations! With relative ease youve just created a fresh virtual device ready for use to test
out your new app.

Now, close the AVD Manager to go back to Android Studios main view. Now that youve
configured everything, theres but one step left
Click the Run button. It looks like a play icon.

A new window will appear, asking you to choose the device you wish to test your App on. You
currently have no devices running, so lets start the AVD you just created. Ensure the Launch
Emulator radio button is checked and your AVD is selected in the drop down menu, then click
OK.

Note: If you get an error that says This AVDs configuration is missing a kernel file!!, check to
make sure that you dont have the ANDROID_SDK_ROOT environment variable set from a
previous installation of the Android SDK. See this thread for more troubleshooting tips.
You may have to wait a while as the emulator loads, and you may even need to try it more than
once for the emulator to get it right, but once its ready, you should see something like this:

Congratulations! You made your first Android app!


Android Apps used to be something you only interacted with on the consumer side, but now
youre a creator. Theres power and possibility in that. Its worth taking a moment to think about
where you might want to go with this newfound ability.
When youre ready, you need to revisit something I quickly glossed over earlier testing on
devices.

Navigating the Android Candy Store


One of Androids advantages, the diversity of devices that can run the platform, is also a major
complication for developers. You have to consider just about everything, such as the items on the
following non-exhaustive list, to be variable:

Screen sizes, both physically and in terms of pixels

Processor speed

Screen density, or the number of pixels per mm

The ratio of the screen width to the screen height

The number of simultaneous touches the touchscreen can register

The quantity and positioning (front vs. back) of cameras

Bluetooth capabilities

Platform and software versions

If you want to make an App that will run on a hundred different devices, how can you tell if its
going to work? Well, there are six main strategies I can recommend:
1. Nail down your target
2. Filter your manifest
3. Check Androids best practices
4. Emulate
5. Pick at least one representative device
6. Fake other screens on your device
Lets go through them one by one.

1. Nail down your target


Does your App have some specific, indispensable hardware or software requirement? What about
nice-to-haves? Take stock of device needs early, so that if your App is camera-based, or
communicates with a specific product through Bluetooth, youre ready to target your App to
devices with those capabilities.
Check the often-updated Android Dashboards to see the prevalence of platform versions as well
as screen sizes and densities. You can see, for example, that your choice in this tutorial to only
support Ice Cream Sandwich and higher will lose you just over a quarter of Android users. Its a
reasonable sacrifice in your case.

2. Filter your manifest


Once youve determined your Apps requirements, you need to let Android know about them.
That way, the Google Play Store can keep non-compatible devices from purchasing your App.
This will save you a lot of frustration and poor reviews from users who might have downloaded
your app, only to find a strange error awaiting them. It wont, however, absolve you from
communicating in any marketing materials the list of devices your users should expect to be able
to run your App on.
The device features you need should be listed in a file. This file, available in every project, is
called the Android Manifest. This is an XML file that contains all the high-level info about your
App. Remember when you chose API 15: Ice Cream Sandwich as the minimum SDK when you
created the OMG Android project? That choice needs to be reflected in your Android Manifest.
Find your AndroidManifest.xml file on the left side of the Android Studio window, likely
under app/manifests, and double-click it to open it up. You will see a few elements contain
values, but nothing that looks like it determines what SDK is used in your App. Thats fine, lets
just add it in. Add the following to your Android Manifest above the application XML tag.
<uses-sdk
android:targetSdkVersion="21"
android:minSdkVersion="16" />

Looking good. Youve just told your Android App what version of Android it is targeting and
what the minimum version a device needs to run it. Or have you? Mouse your cursor over your
newly added XML and you should receive the following message.

As the message politely tells you, your newly input values are being overridden by a Gradle
Build Script. Lets go see where this happens, double-click on the build.gradle (Module: App) file
in the Gradle Scripts folder and you will be presented with something like this.
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.darrylbayliss.omgandroid"
minSdkVersion 16
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}

There are quite a few things going on here, but for now you will focus on just one part the
defaultConfig element. Inside its curly brackets you will see some familiar looking values that
are affecting your App when it is being compiled. This was what the message in your Manifest
was warning you about. Fortunately, it isnt a concern, but it is something worth understanding.
Whenever you click Run in your main project window, any values within the defaultConfig
element of build.gradle are used to populate some additional information into your
AndroidManifest.xml file. The reason for this is to make use of the flexibility of the Gradle Build
Toolkit.
Before Android Studio, things such as trying to build multiple versions of an App from the same
project was something of a pipe dream. An App project only has one manifest file to declare its
features and rules so if you wanted to test different configurations of your App, it would be a
long and labored process because you would have to make your changes, compile the App and
then repeat this process until you were happy with the results.
The arrival of Gradle changes all that, allowing for multiple bespoke versions of your App to be
created using specific rules you can set yourself. Project dependencies can be linked to from
remote code repositories, ensuring every time you build your App you are using the latest version
of 3rd party libraries. You can even set rules up to test your APK using a variety of source files
during the build process.
Gradle makes use of Groovy syntax, a Java like language, so if you are intent on learning Java
then you will easily pick Groovy up as well.
You can learn more about Gradle and its treasure chest of features right here on the Android
Developers website.

3. Check Androids best practices


Theres a great list of best practices to address compatibility issues thats available on the
Android Developer site. Some of the most useful tips include:

Use density-independent measurements in your layouts, so your specifications will scale


along with the screen.

When putting together layouts, use relative widths and heights instead of absolute values.

Putting in several versions of the same image file, tailored to different screen densities,
can also be a good idea.

The tutorial will discuss these in more detail in Part Two, when you lay out views in XML.

4. Emulate
When you set up your Emulator earlier, you saw how many options you have to work with
different screen sizes. If you used the stock emulator then you also saw how slow it can be. As
mentioned earlier, there are ways to improve it and alternative emulators all together you can
make use of to try your App on a huge variety of configurations.
If the stock emulator isnt for you, try them out and see what works best.

5. Pick at least one representative device


The most expensive option, unless you already own an Android device, is to go out and buy one.
I recommend trying to find a used, unlocked device from the Google Nexus series. If your
budget is tight, go two generations back, which at the moment would mean a Galaxy Nexus. Of
course, if youve got the money, you can go for the new snazzy Nexus 5!
With all the time you will save avoiding the emulator, if you continue on with Android (which I
hope you will!), it will definitely be a worthwhile investment.
If you have a device, you dont need any silly Provisioning Profiles. You just need to turn on
USB debugging for your device. Sometimes the checkbox option is available just by going to
Settings > Developer Options on your device. Check these instructions for more details.
Other times, you have to do some weird shenanigans. I cant make this up! A direct quote from
Android: On Android 4.2 and newer, Developer options is hidden by default. To make it
available, go to Settings > About phone and tap Build number seven times. Return to the
previous screen to find Developer options.
No matter if you had to do a little dance or whistle a perfect C to reveal the option, once USB
debugging is on, you can go back to the Run/Debug Configurations screen and set your Target
Device to USB Device. This will serve you well for the rest of the tutorial.

6. Fake other screens on your device


If you are lucky enough to have a device and have enabled USB Debugging on it, then you have
another testing advantage: you can use it to fake other screen sizes. Heres how.
Open your Terminal as you did earlier, when you checked for the JDK. Then locate a tool called
the Android Debug Bridge (adb). With early versions of Android Studio, it will be in the
/Applications/Android\ Studio.app/sdk/platform-tools directory, or wherever you installed your
copy of Android Studio, if elsewhere. Later versions of Android Studio do not come with the
Android SDK bundled in and so you might have your Android SDK installed in a totally
different location.

You can use the following command at the Terminal prompt to see if adb is available in your
system PATH:
adb version

The result should be something like this:

Note: If the adb version command results in an error message, your Android SDK folder is
probably not in your PATH. Then youd need to find the exact location of the Android SDK and
change to the correct folder (as in the first steps in the screenshot above) and prefix any adb
commands with ./. Alternatively, you can add the adb path to your PATH.
The adb version command is just an example to show you how to call adb from the command
line. It can run all sorts of commands and you can get a list of available commands by typing adb
help.
If not already set up, you can optionally add the Android SDK platform tools folder to your
$PATH so that you can run adb from anywhere on your system. You should only do this if you
are familiar with UNIX and feel comfortable doing so.
With your device plugged in and with its screen turned off, type the following:
adb shell wm size 640x480

And then type:


adb shell wm density 160

This represents a screen size of 640480 pixels with 160 pixels per inch pixel density.
Note: In Android versions earlier than 4.3 Jelly Bean, these commands are slightly different, as
documented here.

When you turn the device screen back on, you should see that the resolution has changed to
match the new values you entered!
Feel free to turn the screen off, try another set of dimensions and turn it back on again.
To return your device to its normal settings, type:
adb shell wm size reset

And then type:


adb shell wm density reset

So you could get a full-size tablet (like a Nexus 10, perhaps) and then easily simulate all sorts of
smaller devices, without having to use the emulator! If you are trying this with a device that has
a relatively small screen then its not really worth going beyond the dimensions of your screen as
it will begin to display elements offscreen.
I hope that information helps you navigate the Gingerbreads, KitKats, Jelly Beans, and all the
other varieties of Android candy. Now, back to the app at hand

So WHY did that work?


Youve got your first app behind you. To start making changes and adding cool features, its
necessary to get a working knowledge of whats going on behind the scenes.
Take a look at the Project section of Android Studio, with the files and folders on the left side of
the screen. You may need to press the little tab on the edge (see below) if the project explorer
isnt visible at the moment.

Browse around for a few minutes without any explicit instructions, expanding and collapsing
folders and double-clicking on files to see their contents in the main window. If you notice any
trends, great. If it all still looks cryptic, not to worry!

Android Project Structure: The Team


Every great team is composed of people who play different roles. Do you want to do the job
right? You need the right team. Android Projects have a few key elements and each has a role to
play:
1. Java: The Professional
2. Resources: The Artist
3. AndroidManifest.xml: The Boss
4. Intent: The Job itself

Java: The Professional


Its the job of your Java code to get things done. Your code is all going to be in the src/main/java
directory under your main project folder. You will be given all the code you need to complete

this tutorial, but if you want to learn or refresh your Java knowledge, here is a nice online
interactive tutorial.
It will be worth your time to learn more and more Java as you explore Android development.
Your team is relying on the professional.

Resources: The Artist


Its not enough to just get the job done. It needs to be done in style. Your App is never going to
stand out unless it has great icons and images, well-designed layouts, engaging copy text, and
maybe even some smooth animations.
Initially, the app/res (Resources) folder contains:

Drawable folders that hold images just the default launch icon for now.

The layout folder with XML that represents the screen designs.

The menu folder with XML of the items that will appear on the Action Bar. More on that
later.

The values folder with XML containing dimensions, strings, and styles.

AndroidManifest.xml: The Boss


Someones got to call the shots. That someone would be the Android Manifest. This XML file
informs your system of the apps hardware and software requirements and contains your apps
name, icon, and version.
The manifest also filters the Intents coming in. You need a job done by your app? Talk to the
boss first. Now, more about the jobs themselves

Intent: The Job itself


Want to show the user a screen? Want to navigate to a website? Whatever the job is, in Android it
is going to take the form of an Intent. If you come from an iOS background, pay close attention
because this is a very Android concept.
The Android system knows that you will potentially have a lot of Apps on your device, and
wants to make it easy for them to talk to each other. So, it allows you to send and receive what
are essentially requests for jobs to be done.
A job could get picked up by your Apps own boss (the manifest) or another App. When creating
an Intent, its up to you to either write it very generally to have the option of picking from

several Apps to perform the job (implicit), or very specifically to follow a certain path (explicit).
Youll see an example of each type if Intent later in this tutorial.
For an immediate example, your App already has an Activity called MainActivity. Your
manifest has it labeled with an intent filter that causes the MainActivity to launch when the user
selects the App icon from their home screen. You could potentially move that filter to another
Activity and then that activity would launch instead of MainActivity. Basically, the App does
whatever the boss says.
If you dont fully grasp everything about Intents right away, dont worry. Just keep the concept
in mind as you see Intents throughout the code, and eventually you will start to get an idea of
their potential.

Putting a Personal Stamp on Your App


Youve made your first App, but whats the first thing you always want to put on any of your
work? Thats right, your name!
Navigate to res/values/strings.xml and double-click the file. When you open the file, youll
see three string resources in XML.
These resources are accessed in different places, but it is very convenient to have all of the text
used in your App in one file. If you need to translate it, or if your marketing coworker tells you to
remove all the nerdy references from your App, it will be easy to make all the changes here.
Change the hello_world string. That string is the one that the app displays on the screen. So,
change it to something more personal that incorporates your own name something like:
<string name="hello_world">Darryl is learning Android!</string>

So remember: When you launch the App, youre essentially doing the same thing as sending a
launch Intent to the manifest. As the boss, the manifest takes a look at the Intent and decides
it has the perfect fit for the job: MyActivity. The Java does the heavy lifting of opening the
screen, but for what to display it goes and asks the artist, eventually leading to strings.xml.
Click Run. When the App launches again, youll see your personalized message!

Congratulations! If you have a device, you can go around showing off your new app to your
friends or take a screenshot from the emulator and send it to them.

Youve entered the world of Android. Youve set up your development environment (no easy
task!), created your first app, run it on an Emulator or device, and changed the App so that it
specifically addresses you. Great job!

Updating With the SDK Manager


This tutorial will work with whatever SDK version you downloaded with Android Studio, but as
mentioned earlier its a good idea to always keep your SDK versions and Android Platform Tools
up-to-date.
To access the SDK Manager quickly from your project, click the
easily download or update your Android SDK components.

Android Tutorial for Beginners: Part 2

Darryl Bayliss on November 11, 2014

button, which allows you to

Update note: This tutorial was updated for the latest version of Android Studio by Darryl
Bayliss. Original tutorial by Matt Luedke.
This tutorial is the second of three parts. If youre looking to start from scratch, Part One is the
tutorial for you!
The first part of this series covered a lot of zoomed-out Android concepts, as well as the general
structure of Android projects. In this part of the tutorial, youll learn more on the ground
Android: how a layout file works and the specifics of Android layouts and views.
By the time youre done with this section, youll have an app with:

An image from a PNG file;

An editable text field for writing messages;

A button to submit your input;

A text view that shows your most recent message;

A list that displays all your messages;

An option to share your message through Facebook, Twitter, SMS or email; and

A greeting that saves and retrieves your name each time you open the app.

You should already be at the point where you have a Hello World app running on your
emulator or device. At the end of the last section, you changed the text so that it greets you
personally, like mine:

Its great that youve come this far but now its time to take it to the next level! Theres a lot
to do, so lets get to it!

Getting Started
Looking ahead, the first thing you should do is check that youre making your app as simple as
possible. You dont want to introduce additional complexity unless its needed since extra
complexity in how something is implemented means that it takes more time and requires more
work if you were to later modify the bits with the extra complexity.
First, open app/res/layout/activity_main.xml. After opening the file, you may have to switch the
editor to Text mode if you cant see the raw XML. Click the appropriate tab at the bottom of the
editor pane as shown below.

Note: From now on, this tutorial will always interact with XML files in text mode.
The only thing you need to remove here are the padding attributes that Android Studio
automatically generates in your .xml layout. They look something like this (your values may
vary slightly):
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"

Delete these lines from your layout, your activity_main.xml file should now look like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

Now, double-click on MainActivity.java on the left pane of Android Studio to take a look at your
first piece of Android code.
Pro Tip: A quick way to navigate to any file in your project using OSX is to type Shift +
Command + O. This is the same shortcut used in Xcode!

The only lines you need to remove here are the following:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);

Be careful not to remove the extra curly brace at the bottom that closes the end of your class.
Now that youve finished that bit of cleaning up, youre all set to begin. Its time to bring your
Activity to life!

XML Layout Basics


Android layouts are in XML format, in the form of a tree with a single root and a hierarchy of
views. The hierarchy is very strict and straightforward: each view in the tree is termed the parent
of the views it contains and the child of the view that contains it.
Open res/layout/activity_main.xml. You can see the XML for your activity here. There is a parent
RelativeLayout and a child TextView.
Look at the TextView specifically. You can see that it contains three attributes. Of those, two are
present in every view youll ever put into your Android layouts: layout_width and
layout_height. The values for these attributes can take several forms:

wrap_content: This

match_parent: This

Explicit values: You could set the dimension to a specific number of pixels (Ex: 5px), but
it is usually wiser to use density independent pixels (Ex: 5dp). A dp is a pixel on a
medium-density (mdpi) device, and the number of actual pixels automatically scales for
devices designated as low-density (ldpi), high-density (hdpi), extra-high-density
(xhdpi), etc.

constant value specifies that the view will be just large enough to fit
whatever is inside it, whether thats an image, text or child view.
constant sets the view to be as big as its parent.

In other words, using straight-up pixels would result in your views being all sorts of crazy sizes,
depending on whether a device has 160 pixels per inch or 300 pixels per inch, or what have you.
Who knows! Let the Android system take care of the scaling and just use dp.
Note: Designations like mdpi and hdpi are only general categories. Actual pixel densities are
even more variable, but they are all given the same scaling factor regardless. So dp scaling, while
convenient, is not an exact science.

iOS Developers should be familiar with a similar practice of density independence, using
points instead of pixels in their layouts to account for early iPhone screens not having Retina
displays.
The final attribute of the TextView is simply text, in which you specify the text to be displayed.
This attribute is a good example of how different views respond to different attributes. Adding a
text attribute to a RelativeLayout or a Space wouldnt accomplish anything because, unlike
the TextView, they wouldnt know what to do with it.
But the value of the attribute, @string/hello_world, isnt whats displaying, is it? What you
specify in your layout file is not the actual string to be displayed but rather a string resource ID
identifying the actual text. That way, all your apps copy can be in one place
res/values/strings.xml.
You can command click on the resource ID to be brought directly to the definition in your
resource file.
Now lets look at the parent node in the XML: RelativeLayout. Whats going on there?

Relative Layouts
The layouts in iOS apps used to be in purely absolute terms, like: Place View X at pixels (x,y),
but now iOS developers have AutoLayout. Android developers have always needed to keep
device screen sizes in mind. Layout files are very well-suited for this consideration.
The default project Studio created for you sets you up with a useful layout: a RelativeLayout.
It is currently the parent layout and the TextView element is its child.
A RelativeLayout is an intuitive and powerful thing. It holds a bunch of child views and
positions them in relation to each other. Here are three examples of what you can easily do with a
RelativeLayout:
Example 1: Use layout_alignParentBottom and the similar attributes for top, left and right to
line up a views edge with the corresponding edge of the RelativeLayout, which may or may
not also be the edge of the screen.

Example 2: You can use layout_toRightOf and the analogous attributes for left, above and
below to position one View relative to another.

Example 3: You can use layout_alignRight and the analogous attributes to align a side of one
View with another.

You can see how that could be useful! For now, though, lets move on to the layout type youll be
using for this tutorial.

Linear Layouts
A LinearLayout needs to have an orientation specified, either horizontal or vertical. Then it
lines up its children in that orientation, in the order in which they are specified in your XML.
The children of LinearLayouts dont respond to attributes like layout_toRightOf, but they do
respond to two other attributes: layout_weight and layout_gravity.
Specifying a layout_weight expands the view to a proportion of its parent so that the parent
weight is the sum of all child view weights.
The layout_weight of View X
The sum of all weights of View X and its siblings
Confused? Perhaps the following image might help explain it better.

Notice how the full height of the parent view is split up between the child views based on the
layout weight assigned to each child view.
Assigning a layout_gravity to a view sets its horizontal and vertical positions within its parent
LinearLayout. For example, a view might have a layout_gravity attribute with a value like
left, right, and center_vertical. The previous values can also be combined, like this: top|
center_horizontal.
Then, theres gravity, not to be confused with layout_gravity. While layout_gravity is
about where you place the view itself, the gravity attribute defines how you place the content of
a view within itself. If you want your text to be left or center justified, use gravity.
The following example shows how layout_gravity and gravity work in a vertical
LinearLayout. Note that the top three have a layout_width of wrap_content while for the
bottom three its set to match_parent:

One handy trick, which youll see in just a bit, is that you can nest layouts inside each other. Cue
the theme music from Inception!
You dont want your layouts to be as multi-layered as a Christopher Nolan movie, though. So, if
you start to see your nested LinearLayouts scheme getting out of hand, consider switching to a
RelativeLayout.
Note: There are also performance reasons for considering a simple layout design. Layout weights
require the layout inflater the class which turns the XML into real Views to do a tiny
calculation to put the view together.
Now, modern devices wont have any trouble rendering your basic layouts. But if you were to
make an indefinitely long ListView for instance, one full of cells making copious use of
nested LinearLayouts and layout_weights all those extra tiny calculations could add up.
Before you move on to the next section, open res/layout/activity_main.xml and change the root
node from a RelativeLayout what Android Studio gave you as a default to a
LinearLayout.
To do that, you should replace these lines:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

And this one at the very end of the file:


</RelativeLayout>

With This:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">

And this:
</LinearLayout>

Accessing Views From Within Java


Layouts are primarily the domain of your XML. But there are plenty of visual elements you will
want to create, destroy, change, and trigger from within your Java code!
So first, edit the TextView in activity_main.xml to match the following:
<TextView
android:id="@+id/main_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:text="@string/hello_world"/>

Notice the addition of the id attribute. Using this tag (or attribute, if you prefer) allows you to
access that specific View from within your code, so you can thereafter manipulate the View via
code.
Theres also a change to make in the text tag. The name of the string resource hello_world is a
bit outdated now, dont you think? Right-click on the @string/hello_world part of the line and
then choose Refactor > Rename.

Then, type in textview and click Refactor.

This not only changes the name of the resource ID in your layout file, it also changes the original
resource ID in your strings.xml file. It also renames the resource ID wherever else it might be
used in the project. This is a useful trick to remember when renaming something that appears all
over your project!
Now open MainActivity.java and add the following line above the onCreate method but below
the MainActivity class declaration:
TextView mainTextView;

Android Studio will throw an error at you when you leave your cursor on this line that will look
like this:

The TextView class hasnt been imported into MainActivity.java yet so it doesnt know what a
TextView is. Android Studio can quickly fix that for you. Just tap Alt-Enter on your keyboard
while this error popup is present to automatically import TextView.
Note: It can get tiresome very quickly having to manually import every single component of an
Android App you want to use in a class. Fortunately you can automate this in the IDE settings
window, which you can access by going to Android Studio > Preferences (for Mac) or File >
Settings (for Windows & Linux) and then clicking Editor > Auto Import and ticking Optimize
imports on the fly and Add unambiguous imports on the fly.
Next, add the following code to onCreate after the two existing lines of code:
// 1. Access the TextView defined in layout XML
// and then set its text
mainTextView = (TextView) findViewById(R.id.main_textview);
mainTextView.setText("Set in Java!");

Your MainActivity.java file should now look like this:


public class MainActivity extends ActionBarActivity {

TextView mainTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// 1. Access the TextView defined in layout XML


// and then set its text
mainTextView = (TextView) findViewById(R.id.main_textview);
mainTextView.setText("Set in Java!");

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is

present.

getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

Finally, run your app and look at the results!

The text set via Java code now appears on screen. What are the steps you just took to make that
happen?
1. You added an id attribute to the View in XML.
2. You used the id to access the View via your code.
3. You called a method on the View to change its text value.
Note: You added the code to access and set the text of your TextView in the onCreate method of
your Activity, meaning that the app runs all the code in that block right away when it first
creates the Activity. Activities have strict lifecycles they must follow and its thanks to this that
you can write code that runs at specific points of an Activities life. You can read more about the
Activity lifecycle here.

Buttons and Listeners


Its time to build on your TextView and get more interactive! Next up is a Button.
Add a Button to activity_main.xml, directly after your TextView:
<!-- Set OnClickListener to trigger results when pressed -->
<Button
android:id="@+id/main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:text="@string/button" />

Notice theres an XML comment above the Button, a reminder of how to trigger results.
The layout_margin attributes simply add 20 density-independent pixels of space above and to
the left of the Button to keep your layout from looking cramped. Remember that the value of 20
will be scaled by the screen density of the device to get an actual pixel value.
Youve probably noticed @string/button under the button text property appears in red. If you
hover over it, youll see that the symbol cannot be resolved and thats because you havent yet
defined it.
Open strings.xml and add the following line to the bottom to resolve this:
<string name="button">Update The TextView</string>

Next, open MainActivity.java and add the following right below the previous line you added
to include a TextView variable:
Button mainButton;

Now add the following code to the end of onCreate, after the code you added earlier:
// 2. Access the Button defined in layout XML
// and listen for it here
mainButton = (Button) findViewById(R.id.main_button);
mainButton.setOnClickListener(this);

Again, you see the same three steps as when you added code to access the TextView:
1. You add an id to the View in XML. Or, in this case, you add a view with an id attribute.
2. You access that View in code by using the id.

3. You call methods on that View.


This time, the method you called on the Button is setOnClickListener. What you put in the
parentheses of that method becomes the answer to this question: Which Object is going to
respond when this Button gets pressed?
To answer that question with simply the word this seems a little curt and unspecific, but Java
knows that it means MainActivity itself is your intended listener.
This means that MainActivity has to implement the View.OnClickListener interface. If that
sentence doesnt make much sense to you, I suggest finding an intro on what an interface is and
how to create one, like this one.
Note: An interface is like part of a job description. If Im a young, ambitious Java object, and I
want to be able to put a particular certification on my resume, there are a few methods I have to
be comfortable and capable of performing. The interface is like the checklist I need to pass, or
implement.
If have an iOS/Objective-C background, an interface is comparable to a protocol. In fact, in
object oriented programming the words protocol and interface are used interchangeably.
Android Studio is smart and can help you do the implementation. Simply single-click on this,
which is underlined in red, indicating an issue (in this case the fact that MainActivity currently
does not support the necessary interface). Then, when a red light bulb appears at the beginning of
the line, click on it and select Make MainActivity implement
android.view.View.OnClickListener.

Simply click OK on the next dialog, which lets you know which method(s) Studio will
automatically create for you.

Studio then generates the code necessary to make your MainActivity qualify as a unioncertified OnClickListener.
First, it added a bit to the class declaration indicating that the Activity implements a specific
interface:
public class MainActivity extends ActionBarActivity implements
View.OnClickListener

Second, Studio added a stub for a method you need to implement in order to get your
OnClickListener license (other interfaces may require more than one method to be
implemented): onClick. This method fires when your Button gets pressed.
@Override
public void onClick(View v) {
}

The method currently does nothing. So add the following code to onClick to make it do
something:
// Test the Button
mainTextView.setText("Button pressed!");

Can you tell from the code what should happen? Run your app and see if youre right

The app now changes the text in the TextView when you press the Button. Cool! Youll be
putting this Button to even better use later to submit input.

Adding a Visual and Nested Layouts


Its always fun to include images in your UI. So how about adding an ImageView to show a little
icon? Along the way, youll also get to see how a nested LinearLayout works.
First off, what image will you show? Well, its easiest to start with the image youre given by
default. Its already in your project and heres where to find it.
Use the Project Navigator to expand the res/drawable directory:

You can see a folder with multiple copies of the same image within res. Notice that the file
names have brackets at the end that look like they contain screen density abbreviations.

Indeed, those abbreviations correspond to the pixel density buckets used to classify Android
devices in dots per inch (dpi):

mdpi:

medium

hdpi:

high

xhdpi:

xxhdpi:

extra high
extra extra high

You can even create your own xxxhdpi folder where you can place images for devices with even
higher pixel densities. Personally, I think they should use Roman numerals for the next level up
and call it xlhdpi, but on second thought that would probably be a terribly confusing way to
go
Look inside the drawable directories. Youll see a file named ic_launcher.png. This is simply the
default launch image youre given, at several different sizes for different screens. The Android
system will pick the right one for the device.
Now head back to activity_main.xml and replace the following section:
<!-- Set OnClickListener to trigger results when pressed -->
<Button
android:id="@+id/main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:text="@string/button" />

With this:
<!-- This nested layout contains views of its own -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- Set OnClickListener to trigger results when pressed -->
<Button
android:id="@+id/main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:text="@string/button" />
<!-- Shows an image from your drawable resources -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:src="@drawable/ic_launcher" />
<!-- Closing tag for the horizontal nested layout -->
</LinearLayout>

You just added a new LinearLayout inside the existing root LinearLayout layout, directly
underneath the TextView as its new sibling. You also moved the existing Button into the nested
layout and added a new ImageView, as well.
By wrapping your Button in a second, horizontal LinearLayout, you are able to place a Button
and an ImageView side-by-side horizontally, even as the root layout has a vertical orientation.
As for the ImageView itself, the important attribute is src, to which you give your drawable
image resource. Note the format you use to reference the drawable image. You need to prefix the
file name of your image (minus the file type) with @drawable/.
Run the app, and youll see the new image right beside the button!

Involving the Keyboard


Now its time to get some user input by introducing an EditText. This is a special subclass of
TextView that opens the keyboard and displays what the user types as its content.
Add the EditText XML to activity_main.xml as a sibling to the TextView and the horizontal
LinearLayout. Be careful not to get it caught inside the nested layout! Instead, add it right after
the closing for the embedded linear layout and just before the closing for the root linear layout.
<!-- Displays keyboard when touched -->
<EditText
android:id="@+id/main_edittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"

android:layout_marginLeft="20dp"
android:hint="@string/hint" />

Notice the special attribute, hint. Youre using this text as a placeholder in the input field. The
app will overwrite it once the user starts typing.
As usual, you need to define the string resource for your hint in res/values/strings.xml:
<string name="hint">A Name</string>

Now open MainActivity.java and add a new variable for the EditText (below the other two
existing variables):
EditText mainEditText;

Next, add the following code to the end of onCreate:


// 3. Access the EditText defined in layout XML
mainEditText = (EditText) findViewById(R.id.main_edittext);

The above code, similar to the previous code, simply gets a reference to the EditText control
and saves it in the assigned variable.
Now that you have a reference to the EditText control, you need to do something with user
input. Replace the current contents of onClick with the following:
// Take what was typed into the EditText
// and use in TextView
mainTextView.setText(mainEditText.getText().toString()
+ " is learning Android development!");

When mainButton is clicked, the mainTextView will now be set to display a string including the
contents of mainEditText concatenated with is learning Android Development!.
Run your app, and test this out!

Now you receive user input with an EditText, submit it with a Button, and display it in a
TextView. Very nice! But how about visualizing more than one piece of data at a time?

The ListView
The ListView is a useful control that visualizes a list of items. Its analogous to a UITableView
in iOS.
You define a ListView just as you would any other view in your XML. Add one to
activity_main.xml as a sibling to the TextView, the horizontal LinearLayout, and the EditText
by adding the following lines after the lines for the EditText control:
<!-- List whose dataset is defined in code with an adapter -->
<ListView
android:id="@+id/main_listview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"/>

Wait what? How in the world could setting layout_height to 0dp be a good idea? After all,
no matter what screen youre on, 0 is always going to scale to 0.
Well, take a look at what directly follows: a layout_weight. Since you havent given anything
else in your layout a weight yet, the ListView is going to expand to fill as much space as
possible, no matter what value you give the layout_height.
The general practice, then, is to use a value of 0 so the layout inflater has one fewer dimension to
think about and can get the job done a bit quicker.

Now open MainActivity.java and, add the following variables below the ones youve already
added above the onCreate method:
ListView mainListView;
ArrayAdapter mArrayAdapter;
ArrayList mNameList = new ArrayList();

The one for the ListView makes sense. But what about the others? The others are for supplying
the ListView with data to display. All will be explained in a bit :]
But first, add the following code to the end of onCreate:
// 4. Access the ListView
mainListView = (ListView) findViewById(R.id.main_listview);
// Create an ArrayAdapter for the ListView
mArrayAdapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1,
mNameList);
// Set the ListView to use the ArrayAdapter
mainListView.setAdapter(mArrayAdapter);

Some of that looks familiar by now: finding the ListView using its id. But what else is going
on?
is an example of an adapter, which is basically a go-between so your ListView
can get the data it needs.
mArrayAdapter

Note: I think of a ListView as being a picky sort, as far as Objects go. Its great at what it does
but doesnt want to get its hands dirty with any real data. Its all got to be prepared for it or else
itll throw a fit.
The Adapter, then, is the enterprising Object that is able to code-switch between the rough
language of the datasource and the refined dialect of the ListView.
When you create mArrayAdapter, you have to specify the Context, the target XML view for the
data (simple_list_item_1), and the datasource (mNameList).
But hang on, you didnt write anything with an id of simple_list_item_1! So where is that
coming from? Also what exactly is a Context?
Notice the android.R.layout part before simple_list_item_1. There are several important
concepts here, but lets look at the R bit first. R (or, R.java, if you prefer) is a dynamically
created class which gives you access to the resources in your project. If interested, you can read
more about accessing resources via the R class, here.

As the linked article above explains, you can use the R class to get a resource ID by specifying a
resource type and a resource name. The resource type would be something like string,
drawable, or layout matching the various resource types you see in your project. And thus,
the layout part in android.R.layout.simple_list_item_1 simply specifies that you are
referring to a layout resource.
But what about the android prefix? Why is it there? It is an indicator that you didnt create the
view; its already part of the Android platform. It represents a simple TextView that a default list
cell can use.
The Context is an object that represents the current state of your App. Do you need to access a
specific service for your App to use? Context is your guy. Do you need your App to show a
specific View or Activity? Context is the mastermind behind it.
In this instance, Context is used to create the Views used within your ListView. Remember that
layout resource you are referring to? This is the layout the context takes and converts into a view,
the adapter then populates each view with a value from its datasource.
The datasource in this case is mNameList, which is simply a list of Strings. Its initialized, but
empty. So the next step is to add some data that the ListView can display.
Add the following code to the end of onClick:
// Also add that value to the list shown in the ListView
mNameList.add(mainEditText.getText().toString());
mArrayAdapter.notifyDataSetChanged();

You simply add whatever the user typed into the EditText to the list of names and then shoot a
signal to the adapter to update whats shown in the ListView.
Now run your app.

You should be able to type a name into the EditText, then see the name used in the TextView
and added to a new row in the ListView when you press the Button. Cool!

Detecting List Selections


Looking at the items in a list is cool, but this is an app, and interactivity is even better! So next
youre going to set up a way to detect user selections from the list.
First, modify the class definition in MainActivity.java to add support for another interface. To do
this, modify this line:
public class MainActivity extends ActionBarActivity implements
View.OnClickListener {

To look like this:


public class MainActivity extends ActionBarActivity implements
View.OnClickListener, AdapterView.OnItemClickListener {

All youve really done is add support for a new interface


AdapterView.OnItemClickListener, which, as the name suggests, listens for item selections
from a ListView. MainActivity is really stacking up the credentials!
You should also have a red line highlighting the line where youve just added your new interface,
Android Studio is letting you know that you havent actually implemented the interface yet. You
can fix this easily by clicking the highlighted line, pressing Alt-Enter,clicking Implement
Methods and finally clicking Ok.

Next, add the following code to the end of onCreate:


// 5. Set this activity to react to list items being pressed
mainListView.setOnItemClickListener(this);

The above code sets MainActivity as the listener for any item clicks on mainListView.
Now replace the onItemClick Method that was automatically generated for you with the
following:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long
id) {
// Log the item's position and contents
// to the console in Debug
Log.d("omg android", position + ": " + mNameList.get(position));
}

You may need to use your old friend Alt-Enter to import and use Log.
Well done! Your MainActivity Class has implemented onItemClick and can live up to the title
of being a card-carrying OnItemClickListener.

But whats happening inside onItemClick? Theres a weird Log.d in there, and then something
with a get(position)
Take a look at what youre passing along to onItemClick. In particular, look at int position,
which is an integer equal to the index of the item the user pressed on the list (counting up from
0).
You take that position, as well as the item at that index in your list of names, and log them.
Logging is a very basic, but very useful debugging technique.
Run your app, enter a few values and add them to the list, just as before. Then select an item.
Theres no visible effect for the moment.
With the app still running, look at the bottom section of Android Studio:

The bottom left section of the window contains information about your Device or Emulator, what
processes are running and logs of what is currently happening within those processes. These logs
appear in a console called logcat. It will read off tons of stuff from your emulator or device, the
majority of which is not of much interest to you at this point. The log statements you generated
with your selections are here, but theres too much noise to see them.
Here are some useful ways to filter out the noise and see only what you want:
Notice the option for Log level in a dropdown at the top of the console. When you put your Log
command into code, it specifically was the Log.d command. The d is for debug level. The
levels are:

v: Verbose

d:

Debug

i:

Info

w: Warning

e:

Error

When you select a log level for logcat, it will only show messages at that level or higher. And
the levels start at verbose and go up to error, in the same order as listed above. So, if you select
the log level as Warning, then youll see all warnings and errors but nothing else.
Meanwhile, you can use the text box to the right of the log level drop-down to apply a filter and
show only those messages that contain the text you typed in.
Now that you know this, set the log level to Debug and type omg android into the filter text box.

Great! You now have a clean feed of log statements and you can detect when a certain item gets
selected in your list. The ability to log will come in handy as you create more complicated apps
and want to stay informed of the inner workings of your code.

The Action Bar


Your app has several different views now, and its time to think about other ways to add
functionality. Older Android devices used to have a Menu device button that would display a
bunch of options depending on the situation, but since Honeycomb in early 2011, Android has
used the Action Bar to display any options for the current view.

The Action Bar provides a familiar base for your users. Since its present across apps, making
good use of the Action Bar means a significant part of your apps functionality will be
immediately intuitive to an Android user. Conversely, neglecting the Action Bar would confuse
all your users who expect it to work and that would be weird!
The Action Bar is already in your app it just has no options attached to it yet. That will be
your first order of business next!

Sharing
Soon youll have a chance to show off the fact that youre learning Android, from within your
own app! Youll do this using an intersection of the Android concept of the Intent and the
Action Bar, known as a ShareActionProvider.
One of the advantages of an Intent is that you can construct it in either a specific (explicit) or
generic (implicit) manner. You used an example of the explicit type when you specifically
defined the Intent that launches your app, which the manifest then identifies as MainActivity.
Now youll see an example of the implicit type.
A generic Intention really helps in this case. After all, some of us prefer to share things with
the entire world, and others with just a few friends. Rather than wondering what a potential
users favorite social network might be and integrating them one by one, you can politely tell the
Android device that youd very much like to share a bit of content (thus expressing an Intent),
and Android will graciously take it from there!
Navigate to res/menu/menu_main.xml and open it.

Youll note that theres some auto-generated XML in there, but you dont need it. Replace the
whole thing with this:
<!-- Defines the menu item that will appear on the Action Bar in MainActivity
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:omgandroid="http://schemas.android.com/apk/res-auto">
<!-- Share item -->
<item
android:id="@+id/menu_item_share"
android:title="Share"
omgandroid:showAsAction="ifRoom"
omgandroid:actionProviderClass=
"android.support.v7.widget.ShareActionProvider" />
</menu>

Because your App is running on versions of Android lower than Lollipop, its often the case that
you need to use features that dont exist on previous versions of Android. This means you ether
build your own functionality to ensure users have a seamless experience across multiple versions
or you provide it using 3rd party libraries.
Google provide various App Compatibility libraries to try and reduce this fragmentation issue. In
the XML above, you can see you are making use of the android.support.v7 libraries in your
XML. Making use of the support library now means the code you are about to implement will
work all the way down to Android v7. You can read more about the support libraries here.
Now head over to MainActivity.java and add the following variable underneath the rest of your
variables:
ShareActionProvider mShareActionProvider;
Note: Studio may be confused about which ShareActionProvider you mean, so if it asks, use
android.support.v7.widget.ShareActionProvider. If you have enabled auto imports then

double check it has imported the right one.


Next, you need to add the following two methods to the class the first one,
onCreateOptionsMenu, might already be implemented in the class. If it is, simply replace the
existing implementation with the new one.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu.
// Adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
// Access the Share Item defined in menu XML
MenuItem shareItem = menu.findItem(R.id.menu_item_share);
// Access the object responsible for
// putting together the sharing submenu
if (shareItem != null) {
mShareActionProvider = (ShareActionProvider)
MenuItemCompat.getActionProvider(shareItem);
}
// Create an Intent to share your content
setShareIntent();
}

return true;

private void setShareIntent() {


if (mShareActionProvider != null) {
// create an Intent with the contents of the TextView
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");

shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Android Development");


shareIntent.putExtra(Intent.EXTRA_TEXT, mainTextView.getText());

// Make sure the provider knows


// it should work with that Intent
mShareActionProvider.setShareIntent(shareIntent);

Important: If theres an implementation of onOptionsItemSelected in the class, remove it.


Add your imports so they are recognised by your Activity.
gets called once, when the activity first starts. Similar to how you
specified which layout XML file you wanted to use for the activity in onCreate, you now direct
the menu inflater to look at menu_main.xml for the menu items that go on the Action Bar.
onCreateOptionsMenu

From there, you can access the menu item you defined in XML by its id, menu_item_share, and
then you can access its action provider. Previously, you specified that this items action provider
was a ShareActionProvider. So, you can safely cast to that type in your code and hang onto a
reference to it via the mShareActionProvider variable.
Then, you call setShareIntent. This method creates an Intent, but not just any Intent. It
creates an Intent whose action youve set to ACTION_SEND. Its truly as generic as it looks:
youre going to tell Android you want to take the action of sending something.
From there, you set the Intents content type, subject used by email programs and the like,
as the subject header of the message , and text. The text matches whatever is currently in your
TextView. After youve packed up everything the Intent needs to know, you pair it with
mShareActionProvider.
This code will work, but only kind of. As-is, you only call setShareIntent once, at the
creation of the menu. It would be much better to update the Intent whenever the TextView
changes otherwise youre stuck with the initial message forever!
Add the following code to the end of onClick:
// 6. The text you'd like to share has changed,
// and you need to update
setShareIntent();

Here, you simply make sure that the share intent is always up-to-date.
Run the app, and try out the new sharing feature tapping the share icon on the Action Bar
should reveal a number of choices, depending on what is installed on your emulator or device.

The ShareActionProvider automatically puts together an array of possible avenues for sharing
content based on the apps you have installed on a given device. This array of options will differ
from device to device. The emulator will most likely have far fewer options for sharing, whereas
you may have apps like Twitter and Facebook on an actual device and could share through those
networks, too.

Remembering Your Name


Everything youve done so far with regard to user input only persists while the app is running.
But what about between sessions? Lets see some data persistence in action, with a new feature
that will record and remember your name each time you open the app.
There are a few good options on Android to persist data, and the simplest one is
SharedPreferences.
stores data in key-value pairs, meaning that you specify a name (the key)
for a piece of data (the value) when you save it, and you can retrieve it later by using the original
key.
SharedPreferences

Lets see how it works in action, shall we?


First, add the following constants and variable to MainActivity.java (to the same place as the
previous variables):
private static final String PREFS = "prefs";
private static final String PREF_NAME = "name";
SharedPreferences mSharedPreferences;

The above sets PREF and PREF_NAME at the top of the class. Youll use PREF as a filename to keep
your SharedPreferences in a single location. Youll use PREF_NAME as the key for storing your
name in shared preferences.

Note: Its a good practice to use variables for Strings that youll need/refer to multiple times.
That way, if you need to change the string value later, you can do it in one place. Youll also
never have to worry about some weird spelling error creating bugs in your code.
The final line adds a variable named mSharedPreferences for storing a reference to the shared
preferences class. You only need to access it in a few places, but it will be useful to hang onto it.
Add the import into your Class if you havent already.
Next, add the following lines to the end of onCreate:
// 7. Greet the user, or ask for their name if new
displayWelcome();

The new code calls a new method, displayWelcome. So implement that by adding the following
method at the end of the class:
public void displayWelcome() {
// Access the device's key-value storage
mSharedPreferences = getSharedPreferences(PREFS, MODE_PRIVATE);
// Read the user's name,
// or an empty string if nothing found
String name = mSharedPreferences.getString(PREF_NAME, "");
if (name.length() > 0) {
// If the name is valid, display a Toast welcoming them
Toast.makeText(this, "Welcome back, " + name + "!",
Toast.LENGTH_LONG).show();
}
}
Note: While you could conceivably place all the code from displayWelcome directly into
onCreate and it would still work, many people, your humble author included, prefer to keep

method lengths reasonable by calling separate methods for a specific task.


This also means that if the same task needs to be performed from elsewhere in code later on, you
already have a handy method in place for it :]
In the new method, the first thing you do is access SharedPreferences, with MODE_PRIVATE
meaning that only your OMGAndroid app can access the data stored here. This means that your
saved data will not get overwritten by another application which might have used the same key
as you.
Then you simply ask the preferences object for whatever value is stored using the key
PREF_NAME. The second parameter for the method can be used to set a default value to be
returned in case there is no value stored using the key you provide. So, you use an empty String
as the default value here.

Finally, you check to see if the retrieved String actually has any content, and display a message
if so. Your message takes the form of a Toast, which is a short-lived pop-up message that
appears for a bit and then fades away. Give the Toast a message it should display, specify one of
its built-in lengths to remain on the screen and then simply tell it to show. Easy!

Displaying the Name Dialog


What youve set up so far will show your name if the application can retrieve it out of the
preferences. But obviously, thats no use to you yet since you have no mechanism in place to
save your name in the first place!
Youll use a Dialog to achieve that. Dialogs are small windows that alert the user. They may
contain ways for the user to provide input or make choices. Youre going to use an AlertDialog,
specifically.
Add the following code to the end of displayWelcome, creating an else branch for the if
condition thats already there:
} else {
// otherwise, show a dialog to ask for their name
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Hello!");
alert.setMessage("What is your name?");
// Create EditText for entry
final EditText input = new EditText(this);
alert.setView(input);
// Make an "OK" button to save the name
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Grab the EditText's input
String inputName = input.getText().toString();
// Put it into memory (don't forget to commit!)
SharedPreferences.Editor e = mSharedPreferences.edit();
e.putString(PREF_NAME, inputName);
e.commit();
// Welcome the new user
Toast.makeText(getApplicationContext(), "Welcome, " + inputName +
"!", Toast.LENGTH_LONG).show();
}
});
// Make a "Cancel" button
// that simply dismisses the alert
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int whichButton) {}


});
}

alert.show();

The app will reach this else condition when there is no valid name saved using the PREF_NAME
key. You use an AlertDialog.Builder to give your AlertDialog a title, a message, and an
EditText in the center for the user to type in their name.
Then, you add two buttons to the AlertDialog: a positive and a negative button. The first thing
you define for each is the text displayed on the button OK and Cancel are pretty standard
choices. The second thing you define for each button is an OnClickListener.
This time your OnClickListeners are specifically DialogInterface.OnClickListeners, and
you are defining them right away. Notice how the parameters for onClick are slightly different.
For the positive buttons listener, onClick does quite a bit. First, it reads the name that the user
typed into the dialogs EditText.
It then saves that name into SharedPreferences using a helper called a
SharedPreferences.Editor. You simply tell the editor what to save and where, tell it to
commit the changes, and thats it!
Finally, it displays a Toast identical to the other welcoming one.
The negative buttons listener is far simpler: it does nothing! Nothing!
Run your app and check out your Dialog.

Type in your name, press OK and see the Toast greeting. From now on, your app will remember
your name and greet you each time you launch it!

Where to Go From Here?


You covered a lot of UI concepts in this part of the tutorial! Take a few minutes to play around
with your app a little, maybe sharing something with a friend!
You can get the full source code for this part of the tutorial on GitHub or as a .zip.
Those looking for a challenge should try:

Setting up the EditText to expect names as its input so that it capitalizes first letters.

Dismissing the keyboard associated with the EditText.

Making the Done button on the keyboard do the same thing as the Update TextView
button.

Modifying font sizes on the various views.

Hopefully you have found this helpful! If you have any comments or questions, feel free to leave
them below. And of course, dont miss Part Three, in which you set up your app to interact with
data online!

The Android robot is reproduced or modified from work created and shared by Google and used
according to terms described in the Creative Commons 3.0 Attribution License.

Android Tutorial for Beginners: Part 3

Darryl Bayliss on November 12, 2014

Update note: This tutorial was updated for the latest version of Android Studio by Darryl
Bayliss. Original tutorial by Matt Luedke.
This tutorial is the third and final part of the series devoted to helping you make your first
Android app! Check out Part One to get started with Android and Part Two to learn more about
Android UI and project structure.

In this final part of the tutorial, youll learn how to leverage the powerful capabilities of the web
to search and display data and images. More specifically, youll make an app that searches the
Open Library API a database of over 20 million books , displays information and cover
images of the books it finds, and allows you to recommend books to friends!
When youre done, youll know how to:

Add powerful third-party libraries to your app via Gradle;

Access a typical RESTful API;

Understand JSON format and parse JSON results;

Responsibly download web images without affecting your UI performance;

Customize list cells with multiple views; and

Build intuitive native app navigation between activities.

These are very useful and transferable skills for all sorts of Android apps youll want to make in
the future.
To begin this part of the tutorial, you should be at the point where you have an app that takes user
input, lists names, and shares messages through social networks. Your app should also ask for
your name when you first open the app and greet you by name thereafter. The final version of the
source from Part 2 is also available on GitHub or as a .zip.

So the personal part is done now its time to interwebify!

Getting Started
Its time to do a bit of rebranding. No longer is this just a little demo app it is a book search
and recommendation engine!
The default Android icon can only take you so far. Download the following files and drag them
onto the src/main/res/drawable-hdpi directory to add them to your project:

ic_books.png

img_books_large.png

img_books_loading.png

Click OK when asked to confirm the move.

Your src/main/res/drawable-hdpi directory should now look something like this:

Note: When importing your images you may receive an error saying Refactoring cannot be
performed when importing images. If that is the case try to drag your images into the project
again whilst holding the Alt key to resolve it.

Only the hdpi assets are provided here. For future projects, it is a good idea to add assets for the
other dpi values as well.
If you have trouble finding the hdpi folder in the drawables folder. Studio may be defaulting to
its Android project view structure. Change this to Project by clicking on the large button to
the left just above the project hierarchy on the left. Once you have imported the images you can
change back if you prefer
Open AndroidManifest.xml. As you recall, this is the boss of your app. If you want to change
the apps icon, you need to talk to the boss.
Find the opening application tag and change the icon attribute line from:
android:icon="@drawable/ic_launcher"

To:
android:icon="@drawable/ic_books"

From now on, the app icon will be a stack of books instead of the default Android icon.
Depending on your Studio version (and/or SDK version) you may also see that the application
has an attribute for setting the application name. Youre going to update the application name as
well, but not in the manifest.
First, while youre still looking at the manifest, you need to let the manifest know that you plan
to start accessing the Internet. Between the uses-sdk and application tags, add the following:
<!-- NEED TO ADD TO BE ABLE TO GO ONLINE AND GET DATA -->
<uses-permission android:name="android.permission.INTERNET"/>

If you dont let the boss know your plans, it wont file the appropriate paperwork with Android
to make the web call happen. But now youre good to go.
Now its time to change your apps name. Open res/values/strings.xml and replace the strings for
everything except action_settings with the following new values:
<string
<string
<string
<string

name="app_name">Bookmaster General</string>
name="textview">Search For Books!</string>
name="button">Search</string>
name="hint">Title and/or Author</string>

Thats right I used the title Bookmaster General.


Finally, remove this line from onCreate in MainActivity.java:
mainTextView.setText("Set in Java!");

Run your app, your device or emulators home screen should reflect the name and icon updates.
For example:

Now that youve rebranded your app, its time to start adding the web interactions!

Networking Considerations
There are a lot of things to keep in mind when adding networking capabilities to your app.
For example, you need to consider how to keep all the network interactions off the UI thread, so
that the user can continue to use your app without everything locking up until a download
completes. If you were using an app and it became completely unresponsive for lengths of time,
youd get pretty frustrated!
You will also find Android will ask your user if they would like to quit an unresponsive App,
which isnt great for your App if people are scrambling to leave it as quick as they can.
Thankfully, you can solve issues such as this by simply using third-party libraries. These have
been specially designed and supported by Android experts to facilitate networking. Some of the
most well-regarded include Retrofit, Volley, and Android Async Http. For the purposes of this
tutorial, youll use Android Async Http.
Image downloads are also a consideration since each image takes time to download. Also, in the
case of a list of books, if you have your list set to download images as needed, you might find
that you end up downloading the same image over and over as your user scrolls through the list
of items. You really dont want that type of behavior. Youll use another third-party library called
Picasso to manage image downloads for you.
Note: The old-fashioned way to incorporate third-party libraries into your code was to download
a zipped-up .jar file, copy it into your code and then include it in your projects build path. Its

not too difficult, but the larger inconvenience is what to do when the library updates, or if you
need to share your project with teammates.
A way to easily manage your projects dependencies would sure be great! That leads us to
Gradle.

A Glance at Gradle
When you created your project in Android Studio, you may remember mentions of Gradle and
Maven. Refer to Part One if you need a reintroduction. Now youll see them in action.
Open build.gradle. Note that there are two build.gradle files in your project. You want the one
thats within the app folder not the one at the project root level:

Some of the stuff happening in here is beyond the scope of this tutorial, but if you become
serious about Android development, I recommend looking into Gradle a little more, starting of
course, with the Gradle website. For now, just notice that the Android plugin is being applied to
the project (apply plugin: 'com.android.application').
Scroll down to the area labeled dependencies. There may already be a support library listed
there, or it may be empty. Youre going to add two new libraries.
Add the libraries like this:

dependencies {
...
// there may or may not be a support library above these
compile 'com.loopj.android:android-async-http:1.4.4'
compile 'com.squareup.picasso:picasso:2.1.1'
}

Then find the Sync Project with Gradle Files button on the Studio toolbar and press it. It looks
like this:

Note: If you get an error that says requires compiling with JDK 7, you should upgrade your
SDK to JDK 7. You can download it here, then follow the prompts to set your SDK folder to
/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home.
Believe it or not, thats it! Just like that, youve included the Android Async Http and Picasso
libraries in your project and you can start using them whenever you like.
Its so easy because both of these libraries are available via the Maven Central Repository, to
which your project already contains a reference. You can see this in your root folders
build.gradle file, it looks like this.
repositories {
jcenter()
}

So, when you tell Gradle which libraries youd like to use, it simply grabs them from the source
and youre good to go.
Note: jcenter() is a Gradle method that connects to a repository which is a superset of the
Maven Central Repository. In early versions of Android Studio the default repository set by
Gradle was Maven Central, you still change it back by changing jcenter() to mavenCentral().
jcenter however is thought of as being faster and more responsive whilst still providing all the
libraries available on the Maven Central Repository. So lets leave this alone.
If you need to include any libraries which are not available on the Maven Central Repository,
then youd still have to go through the old school method of copying the source (or the library)
into your project. But most of the time, you wont have to go through all that pain since the
Maven Repository contains a lot of third-party libraries for you to use. So youll probably be
able to find an alternative to the library youre interested in. If interested, you can even browse
all the libraries available on the Maven Repository.

JSON Basics

Great! Now its time to meet your datasource: the Open Library API. Its a constantly-updated
database of books, searchable by author and title. The wealth of data is enormous!
Try this query as an example: http://openlibrary.org/search.json?
q=hunger+games+suzanne+collins
This is a relatively simple URL to understand; whatever is typed in after the ?q= is the query
string that will be used to search the database. Feel free to change it to a different author
name/title and compare results, remembering to use + to separate words.
The result is in the form of a large JSON response. Take a minute to look around at the sort of
data the response includes.
If youre not familiar with the JSON format, I suggest a quick glance through the JSON page.
The basics are that there are two ways data can be arranged in JSON: arrays and objects.
JSONArrays

list objects of the same type. For example, a list of books might look like this:

["The Hunger Games", "Harry Potter and the Sorcerer's Stone", "A Game Of
Thrones"]

are a collection of key-value pairs. For example, a very simple object describing a
book might be:
JSONObjects

{"title" : "The Hunger Games", "author_name" : "Suzanne Collins"}

The results from your queries to the Open Library API are really just expansions on those two
basic structures. They are larger, and nested into several levels, but the ideas remain the same.

Creating a Query
Now that you know roughly what to expect from the datasource, its time to set up the code to go
make a sample query!
Add the following variable to your growing list at the top of MainActivity.java:
private static final String QUERY_URL = "http://openlibrary.org/search.json?
q=";

The above is simply a reference to the URL youll be calling. Its much better to hold this URL
as a static String, so you dont have to go searching through your code for it. Remember that
youre going to append the search string after the ?q=.
Next, add this new method anywhere in your MainActivity.java Class:
private void queryBooks(String searchString) {

// Prepare your search string to be put in a URL


// It might have reserved characters or something
String urlString = "";
try {
urlString = URLEncoder.encode(searchString, "UTF-8");
} catch (UnsupportedEncodingException e) {
// if this fails for some reason, let the user know why
e.printStackTrace();
Toast.makeText(this, "Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
// Create a client to perform networking
AsyncHttpClient client = new AsyncHttpClient();
// Have the client get a JSONArray of data
// and define how to respond
client.get(QUERY_URL + urlString,
new JsonHttpResponseHandler() {
@Override
public void onSuccess(JSONObject jsonObject) {}
@Override
public void onFailure(int statusCode, Throwable throwable,
JSONObject error) {}
});
}

handles the network call to the API. It encodes the input searchString into URL
format, then appends that to the base URL you specified at the top of the class.
queryBooks

Calling new AsyncHttpClient() simply creates an instance of the HTTP client. Its got a lot of
great methods built-in, but the only one you need here is get(String url,
ResponseHandlerInterface responseHandler).
The get method takes in two parameters:

String url

JsonHttpResponseHandler,

is simply the URL from which youd like to fetch data. This parameter will
be made up of base URL defined at the top of your class, plus the search string you will
add later.
which you define now, even though you dont know
whether the network call will succeed or fail, or how long it will take either way. It
contains methods called onSuccess and onFailure to respond to the two cases once the
handler does get a response from the server.

You might have noticed that onSuccess and onFailure are currently method stubs with no
code. Fix that by fleshing out the onSuccess to match the following:

@Override
public void onSuccess(JSONObject jsonObject) {
// Display a "Toast" message
// to announce your success
Toast.makeText(getApplicationContext(), "Success!",
Toast.LENGTH_LONG).show();
// 8. For now, just log results
Log.d("omg android", jsonObject.toString());
}

Next, implement onFailure as follows:


@Override
public void onFailure(int statusCode, Throwable throwable, JSONObject error)
{
// Display a "Toast" message
// to announce the failure
Toast.makeText(getApplicationContext(), "Error: " + statusCode + " " +
throwable.getMessage(), Toast.LENGTH_LONG).show();
// Log error message
// to help solve any problems
Log.e("omg android", statusCode + " " + throwable.getMessage());
}

In both cases, you simply present a Toast and log the results. Soon, though, the success case will
get a lot more exciting.

Making the API Call


queryBooks is a great method and all, but
Button to complete the search capability.

it still needs to be hooked up to the EditText and

Fortunately, thats pretty simple. In MainActivity.java, find onClick and replace everything
inside the Method with this:
// 9. Take what was typed into the EditText and use in search
queryBooks(mainEditText.getText().toString());

Now, every time the user taps the button, this method takes the users input in the EditText
control and queries the Open Library for books and authors matching that string. Run your app
and try it out to see what happens!
Note: If Studio runs into any issues with its Gradle sync, you may get a NoClassDefFoundError
upon querying. If so, not to worry simply select Build > Rebuild Project and try again!
Remember that you havent yet hooked up the results to anything that will display them on the
screen. You will still see something happening though, open LogCat and you can see the
resulting JSON spilled out whenever the API call finishes.

This is already exciting and clearly has the potential to be something cool very soon! But its still
just a jumble of data. Your next challenge, then, is to display this data on the screen in a more
organized manner.

Creating the List Rows


First, you need to set up the layout for each of the rows in your list. A simple row of text wont
cut it anymore you need space for a thumbnail image on the left and then two rows of text for
the title and author, respectively. A layout which would look something like this:

Right-click on the res/layout folder in the Studio left pane, and select New > Layout resource
file.

Name your file row_book.xml with a root element of RelativeLayout, then click OK.

The new file will open in Design mode. So, switch to Text mode, as before. Now change the
layout_height attribute from this:
android:layout_height="match_parent"

To this:
android:layout_height="75dp"

You simply set the layout to have a specific height instead of matching the height of the parent
container.

Next, youre going to add three views inside the RelativeLayout, and then youll witness a few
of the capabilities of this type of layout in action. First, add the thumbnail view:
<ImageView
android:id="@+id/img_thumbnail"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="25dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:scaleType="centerInside"/>

The ImageView has the width and height set and theres a little margin to the left of the picture.
This is stuff youve seen before.
Then it gets interesting with layout_alignParentLeft and layout_centerVertical. These
attributes are available since this ImageView is a child of a RelativeLayout. Because of these
two attributes, the ImageView stays tight to the left of the cell with that margin intact, and centers
vertically.
The last attribute, scaleType, specifies how youd like the image to display within the amount
of space its given. Especially given the unpredictable list of screen sizes youd have to support,
its often important to set this beforehand.
Using centerInside means that youll preserve the aspect ratio of the image and that both
dimensions will fit inside the given space. You might, however, have some blank space above
and below the image if its too short, or space on the sides if its too thin. If youre interested,
you can read up on the various ScaleType options.
Next, add a TextView for the books title:
<TextView
android:id="@+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_toRightOf="@+id/img_thumbnail"
android:layout_alignTop="@+id/img_thumbnail"/>

Read through the XML first and see if you can tell whats going on. The commands should be
starting to make a bit of sense by now. The only thing that might give you pause might be the
@+id/img_thumbnail bit but thats just a reference to another control by ID. In this case, the
ID refers to the ImageView you added previously.
Basically, the title will sit to the right of the thumbnail, such that the top of the title will be at the
same height as the top of the thumbnail. Theres some space in between the two controls, as well.
Finally, add the TextView for the authors name:

<TextView
android:id="@+id/text_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/text_title"
android:layout_alignLeft="@+id/text_title"/>

By now, these attributes should all make sense. The authors name will be below the title, with its
left side aligned to that of the title.
Note: One quick thing before moving on. Attributes for children of RelativeLayouts often
reference other children using IDs, as you saw just now. Make sure that the references dont get
circular (two attributes that depend on each other), or else your XML wont inflate!

Adapting JSON for a ListView


In Part Two, you made a ListView, at which point I mentioned that ListViews are a bit picky.
They dont want to deal with the data directly you can hardly blame them after seeing that
confusing JSON response that popped into LogCat earlier. The simple, built-in adapter you used
in Part Two wont cut it here; you need a custom one.
Right-click on the com.example.omgandroid folder (or whatever package name you used when
creating the project) and select New > Java Class.

Then type in JSONAdapter as the new class name, make sure the Kind is set to Class and then hit
OK.

Once you have your new class open in the editor, add the following code so the class looks like
this:
public class JSONAdapter {
private static final String IMAGE_URL_BASE =
"http://covers.openlibrary.org/b/id/";
Context mContext;
LayoutInflater mInflater;
JSONArray mJsonArray;
public JSONAdapter(Context context, LayoutInflater inflater) {
mContext = context;
mInflater = inflater;
mJsonArray = new JSONArray();
}

This is still just a basic class, beginning with the first part of the URL youll use to download
images more on that when you implement the image download code.
Next, there are three simple variables:

A Context. Your old friend Context. Remember Context is the object that lets other
objects know what is happening in your App. Here Context is going to help Picasso, the
image downloader Library, display the images you download in your App

A LayoutInflater. You need this to inflate a View out of that list item XML you just
wrote.

A JSONArray. This is the datasource that will be coming in from the server in response to
your query!

The JSONAdapter method is the class constructor thats what you call when you create a new
instance of JSONAdapter. So, anyone who wants to ask JSONAdapter to do anything has got to

create an instance of it first, which in turn requires submitting the Context and LayoutInflater
via the constructor.
The constructor currently simply saves the passed in references and creates an empty JSONArray.
Youll pass the real data to the class after the search results are in.
Now you need to convert this class into an actual Adapter class. This is quite easy in an objectoriented programming language like Java simply change the top line of the class from:
public class JSONAdapter {

To:
public class JSONAdapter extends BaseAdapter {

Note: Those with a fuzzy grasp of object inheritance and other object-oriented programming
concepts may want a refresher like this one, but in essence, youre saying that JSONAdapter is
going to build on the basics provided by the BaseAdapter class.
Right away, Android Studio will underline the line you just modified in red to let you know that
you need to add more to JSONAdapter before it accurately extends BaseAdapter. Studio isnt
just a naysayer, though it can help, too! Click the underlined line, then click the red light bulb
that pops up next to it, and then select Implement Methods from the menu.

When asked to select methods to implement, make sure all four methods are highlighted and
click OK.

Magically, Android Studio creates four methods for you and the red underlining disappears. This
means that youve satisfactorily extended BaseAdapter.
But all the methods are empty. Its time to go through each one in turn and make them do what
you want.
So, first replace the current implementation for getCount with the following:
@Override
public int getCount() {
return mJsonArray.length();
}

answers the question: How long does your ListView need to be? In this example, the
answer is simply the length of your JSONArray. Each entry in that array represents a book and so
each one gets a row in the ListView.
getCount

Now replace getItem with this version:


@Override
public JSONObject getItem(int position) {
return mJsonArray.optJSONObject(position);
}

getItem returns the book for a given position, counting up from 0. A single book is represented
by a JSONObject. They all just happen to be stored in a JSONArray. So all you have to do is
complete a lookup on the array for the JSONObject at the given position.

Next, replace the stub for getItemId with this code:


@Override
public long getItemId(int position) {
// your particular dataset uses String IDs
// but you have to put something in this method
return position;
}

This can be a very helpful method in some situations, but in this case, you dont really need it.
So, you just set it to position. Imagine a situation where you have a list of books, as a subset of
a larger database, and each book has an ID in the larger database. If you needed to go back and
query for more information based on a certain items ID number, this method would be helpful
for you.

Putting Together the Insta-Row


The last method, getView, answers the ListView when it comes to the adapter and asks: What
should I show at position X?
To begin to answer that question, you first need to create whats called a view holder. Add the
following to the end of your JSONAdapter code (but before the final closing curly brace):
// this is used so you only ever have to do
// inflation and finding by ID once ever per View
private static class ViewHolder {
public ImageView thumbnailImageView;
public TextView titleTextView;
public TextView authorTextView;
}

This class is simply a packager of the three subviews that every row in your list will have. Think
of it as a Do-It-Yourself kit for your list cells. All each row needs to do is get one of these, update
it with the right data based on the row and presto: an Insta-Row!
The trick is that as you scroll around through who-knows-how-many books in your list, the app
shows the data using the same cells, over and over. There are only just enough list cells to fill the
screen, plus a few extras. Keeping all of the list cells in memory, even while theyre off-screen,
would get crazy!
As a view scrolls out of sight, the recycling crew comes by and dumps out everything inside the
view, but hangs onto the ViewHolder. That same view, and the ViewHolder, then get handed
over to a list cell about to scroll into sight.

The re-used view is handed one of these ready-made Insta-Row kits (aka a ViewHolder), and
simply fills the contents of each subview as needed, rather than inflating a brand new view from
XML and creating all those subviews from scratch every single time.
For more details on the view recycling process, here is a helpful blog post about it.
With that in mind, replace the stub for getView with this code:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// check if the view already exists
// if so, no need to inflate and findViewById again!
if (convertView == null) {
// Inflate the custom row layout from your XML.
convertView = mInflater.inflate(R.layout.row_book, null);
// create a new "Holder" with subviews
holder = new ViewHolder();
holder.thumbnailImageView = (ImageView)
convertView.findViewById(R.id.img_thumbnail);
holder.titleTextView = (TextView)
convertView.findViewById(R.id.text_title);
holder.authorTextView = (TextView)
convertView.findViewById(R.id.text_author);
// hang onto this holder for future recyclage
convertView.setTag(holder);
} else {
// skip all the expensive inflation/findViewById
// and just get the holder you already made
holder = (ViewHolder) convertView.getTag();
}
// More code after this
return convertView;
}

If it happens to be the first time for the view, then you need to use your custom row XML using
mInflater and find all your subviews using findViewById. But as mentioned earlier, the view
might already exist in which case you want to skip all that from-scratch stuff.
You use the setTag and getTag methods to hang onto the ViewHolder and easily pack/unpack it
while scrolling around.
Next, you need to handle the image thumbnail of the books cover. Put this new code right after
the // More code after this comment line:
// Get the current book's data in JSON form
JSONObject jsonObject = (JSONObject) getItem(position);
// See if there is a cover ID in the Object
if (jsonObject.has("cover_i")) {
// If so, grab the Cover ID out from the object
String imageID = jsonObject.optString("cover_i");
// Construct the image URL (specific to API)
String imageURL = IMAGE_URL_BASE + imageID + "-S.jpg";
// Use Picasso to load the image
// Temporarily have a placeholder in case it's slow to load
Picasso.with(mContext).load(imageURL).placeholder(R.drawable.ic_books).into(h
older.thumbnailImageView);
} else {

// If there is no cover ID in the object, use a placeholder


holder.thumbnailImageView.setImageResource(R.drawable.ic_books);

In this section, you first get the JSONObject for the precise book whose data you want to display.
Of course, this is dependent on the items position in the list.
Next, you check to see if theres a cover ID for that book. Unfortunately, many books dont have
covers in the Open Library database. So, you look to see if a cover is there by calling
has("cover_i"), which returns a true-or-false boolean. If it returns true, then you parse out
the cover ID from the JSONObject and use it to construct a URL specific to Open Library.
Note: An example URL from this operation: http://covers.openlibrary.org/b/id/6845816-S.jpg
You can change the -S.jpg to -L.jpg for a larger version of the same image:
http://covers.openlibrary.org/b/id/6845816-L.jpg
Once you have the URL, you simply tell Picasso to download it and display it in your
ImageView. You also specify a placeholder image to show while the cover image is
downloading.

If the book doesnt have a cover assigned, you show the standard icon.
Finally, you need to populate the book title and author name. So, add the following code
immediately after the block of code you added above:
// Grab the title and author from the JSON
String bookTitle = "";
String authorName = "";
if (jsonObject.has("title")) {
bookTitle = jsonObject.optString("title");
}
if (jsonObject.has("author_name")) {
authorName = jsonObject.optJSONArray("author_name").optString(0);
}
// Send these Strings to the TextViews for display
holder.titleTextView.setText(bookTitle);
holder.authorTextView.setText(authorName);

This step is similar to the last. As long as the JSONObject contains the title and author name, you
parse the values and set the text of each TextView!

Connecting the List to the Adapter


The last thing you need to do before you can test your newly-webified app is connect the
ListView to the JSONAdapter.
Remove the following code from onCreate in MainActivity.java:
// Create an ArrayAdapter for the ListView
mArrayAdapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1,
mNameList);
// Set the ListView to use the ArrayAdapter
mainListView.setAdapter(mArrayAdapter);

Also remove the following from onItemClick in MainActivity.java:


// Log the item's position and contents
// to the console in Debug
Log.d("omg android", position + ": " + mNameList.get(position));

You dont need any of that simple stuff now that youve got your own souped-up Adapter!
Now, to start using the your adapter class, replace this line at the beginning of MainActivity.java:
ArrayAdapter mArrayAdapter;

With this:
JSONAdapter mJSONAdapter;

Next, add the following to the end of onCreate:


// 10. Create a JSONAdapter for the ListView
mJSONAdapter = new JSONAdapter(this, getLayoutInflater());
// Set the ListView to use the ArrayAdapter
mainListView.setAdapter(mJSONAdapter);

Great! You just created an instance of your snazzy new JSONAdapter, feeding it a Context and a
LayoutInflater. Your Activity can be used as a Context parameter (via the this keyword)
because Activity is a Subclass of Context. Now your adapter is hooked up and can provide your
ListView with the data it needs.
If you were to build and run, though, you would be rather underwhelmed by the results. Even
after inputting a search String, the ListView remains empty. Why?
Because, if you recall, you created your Adapter using its constructor, public
JSONAdapter(Context context, LayoutInflater inflater). That method creates an
empty JSONArray as a placeholder.
An empty list is OK to start with, of course, but it sure would be great to update the list when
your search is done! Thats not happening yet, so thats next on your agenda.

Updating the List Data


To update the list, you need to add an update method to your adapter and then call it from your
activity.
First, add the following method to JSONAdapter.java:
public void updateData(JSONArray jsonArray) {
// update the adapter's dataset
mJsonArray = jsonArray;
notifyDataSetChanged();
}

This method accepts a JSONArray input, sets it as the adapters datasource, and calls
notifyDataSetChanged to refresh the list. The adapter is already set up to know what to do with
the data, so thats all you need!
Now go back to MainActivity.java. Youre going to use your new method to update the list when
the network call comes back. Find the following code in onSuccess, which is embedded within
queryBooks:

// 8. For now, just log results


Log.d("omg android", jsonObject.toString());

Replace it with this instead:


// update the data in your custom method.
mJSONAdapter.updateData(jsonObject.optJSONArray("docs"));

This is simply a call to updateData with the newly-returned query response. As soon as the data
comes back, you dont waste any time you send it straight to the adapter, which whips it into
shape for the ListView!
Its finally time run your app, and search away!

Now you can type a search string into your EditText, tap the Search button and let the
ListView (somewhat) magically populate from your web search. Not only that you can scroll
through all the results and look at book titles, author names, and thumbnails of the cover images.
This is already a pretty cool app!

Showing Progress
One nice feature you may notice missing is some kind of progress bar or spinner to let the user
know your app is thinking. Lets solve that now.
Add the following line to the list of variables at the top of MainActivity.java:
ProgressDialog mDialog;

is an Android class that provides a convienent solution for times when you
want to provide feedback that your App is performing some sort of intensive task. That could be
fetching large files and reading their contents, setting up basic values for the first time the App
run or fetching online content like your current App does.
ProgressDialog

Lets set some initial values, go to your onCreate Method and add these lines at the end:
mDialog = new ProgressDialog(this);
mDialog.setMessage("Searching for Book");
mDialog.setCancelable(false);

Good. Youve told your Activity you want a ProgressDialog to be created with a particular
message and that you dont want the user to have the ability to cancel it. Lets put this to work,
add this line to queryBooks, immediately after creating your AsyncHttpClient:
// Show ProgressDialog to inform user that a task in the background is
occurring
mDialog.show();

You want the Dialog to disappear when the request is over, which could actually be in one of two
spots onSuccess or onFailure. Add the following line at the very beginning of onSuccess:
// 11. Dismiss the ProgressDialog
mDialog.dismiss();

Then add the same line to the beginning of onFailure:


// 11. Dismiss the ProgressDialog
mDialog.dismiss();

Run the app again and do another search.


This time, your Dialog will appear in the middle of your screen and will spin as your networking
call is happening. Much better! Your App users now know when something is happening behind
the scenes thanks to you.

The Detail Activity


Seeing the list of all the books is exciting! The next logical step is to let the user select a book
from the list to see more details or a larger version of the cover.
For this app, youll only show a larger version of the cover. But the techniques you use will pave
the way for the additional challenge of displaying any further details that may interest you. Lets
get started!
First, add the following line to res/values/strings.xml:

<string name="activity_details">Book Details</string>

This is simply to provide a title for the activity. As mentioned before, its good to keep all the
strings in one file!
Next is the layout XML. It wont be complicated. Right-click on res/layout and select New >
Layout Resource File.

Name it activity_detail.xml, with a Root Element of ImageView.

Thats almost it right there. All you need to do now is give the ImageView an id, a default image,
and a bit of margin space for good measure. Edit activity_detail.xml in Text mode to look like
this:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/img_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="25dp"
android:src="@drawable/img_books_large"/>

Thats simple enough. This screen will now show a single ImageView with a 25dp margin all
around, and the default image is img_books_large.
Next, you need to make a new Activity. Right-click on the com.example.omgandroid package
(or the package name you set originally) and select New > Java Class, as before.
Name the class DetailActivity.

This creates a simple, empty class for you. Next, modify the class definition so that your new
class extends Activity, like this:
public class DetailActivity extends ActionBarActivity {

You already know you need to access the ImageView from your layout, so add the following
method to your activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Tell the activity which XML layout is right
setContentView(R.layout.activity_detail);
// Enable the "Up" button for more navigation options
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Access the imageview from XML
ImageView imageView = (ImageView) findViewById(R.id.img_cover);
}

The above code simply tells the Activity to use the simple XML layout you made earlier, and
then grabs the ImageView you need from it. But wait: what is that getSupportActionBar stuff
doing in there?

The Up and Back Buttons


You may have noticed, or simply used it without really thinking about it, the Up button in many
Android apps. The proper Android design of the Up and Back buttons is well-documented here
and is worth a read, but it all begins with enabling the button as you just did.

The other steps for enabling the Up button take place in your manifest. Open
AndroidManifest.xml and add the launchMode attribute to MainActivity so that it looks
something like this:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop">

Note: Depending on your Android Studio version, the package name you selected when you
created the project, and a few other factors, the above might not match what you see in your own
AndroidManifest.xml file exactly. The only thing you need to really worry about is adding the
new launchMode attribute as shown above. You can leave the rest as is.
So, do you recall from earlier in this tutorial about how the manifest is the boss who takes in
jobs in the form of Intents and checks if there is a team member right for the task? Normally,
the manifest would arrange for the system to start a brand-new instance of that Activity every
time.
But, by setting the launchMode attribute to singleTop, youre telling the manifest to use an
already-existing instance of that Activity, if possible. That way, when you use either the Back
or Up button to return to the main screen, your most recent search results will still be there and
you wont have to start from scratch!
Next, add a definition for the DetailActivity to the manifest, immediately after the one for
MainActivity:
<activity
android:name=".DetailActivity"
android:label="@string/activity_details"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>

This looks pretty similar to the definition for MainActivity, except for the stuff about parent
activity. Setting the parent activity tells the manifest which activity should be displayed when
theres a request to go up from DetailActivity.

An Intent to Show the Detail Activity


Now that youve set up your manifest to be aware of your DetailActivity, you need to send it
an Intent to start it! This Intent is going to originate from the MainActivity, when the user
selects a book from the list.

If you recall, the method that executes when a cell is selected from the ListView is
onItemClick in MainActivity.java. It used to log information originally but now is empty. Add
the following code to it:
// 12. Now that the user's chosen a book, grab the cover data
JSONObject jsonObject = (JSONObject) mJSONAdapter.getItem(position);
String coverID = jsonObject.optString("cover_i","");
// create an Intent to take you over to a new DetailActivity
Intent detailIntent = new Intent(this, DetailActivity.class);
// pack away the data about the cover
// into your Intent before you head out
detailIntent.putExtra("coverID", coverID);
// TODO: add any other data you'd like as Extras
// start the next Activity using your prepared Intent
startActivity(detailIntent);

Here, you create an Intent to take you from where you are now (this) to an instance of
DetailActivity. But before you fire off the command using startActivity, theres one more
thing to remember to pack away.
As youve previously seen when you created setShareIntent, you can pack extras into an
Intent in the form of key-value pairs. Since your DetailActivity needs to know the cover ID
to display, you extract that ID from the books JSON data and send it along.
Note: I put in a TODO reminder for an optional challenge to you. If you want your
DetailActivity to do anything more than show an image, you should send along additional
data here.
Build and run your app, and you will be able to click on a list item from your search results to
see your new DetailActivity! You can also navigate back to the main screen using either the
Up or Back button.

Right now, you only see the placeholder image, but you know where this is headed :]
Add the following variables at the beginning of DetailActivity.java (right after the class
definition line):
private static final String IMAGE_URL_BASE =
"http://covers.openlibrary.org/b/id/"; // 13
String mImageURL; // 13

This sets the base URL for cover images on the Open Library API. You also create mImageURL to
hang onto any specific URL so that different methods within your Activity can use it without
needing to create the image URL all over again each time.
Next, add the following code to the end of onCreate:
// 13. unpack the coverID from its trip inside your Intent
String coverID = this.getIntent().getExtras().getString("coverID");
// See if there is a valid coverID
if (coverID.length() > 0) {
// Use the ID to construct an image URL
mImageURL = IMAGE_URL_BASE + coverID + "-L.jpg";
// Use Picasso to load the image
Picasso.with(this).load(mImageURL).placeholder(R.drawable.img_books_loading).

into(imageView);
}

The above code digs into the Intent that brought you to this Activity and sees if it contains a
String with the name coverID. If so, the Picasso Library will download the image, just as you
did in all the row cells. You display a loading image until the desired image is ready.
Build and run, and youll see the actual cover for the book you chose from the list!

Sharing the Image


The last thing to do is allow your users to share these cover images. Youve already seen sharing
in action and the code is almost identical here.
First, add another variable to the top of DetailActivity.java:
ShareActionProvider mShareActionProvider; // 14

This is just another variable to hold a reference to the ShareActionProvider for your
Activity. Make sure you import the right ShareActionProvider. It should match the import in
your MainActivity.java class.
Next, add this new method to the class:
private void setShareIntent() {
// create an Intent with the contents of the TextView
Intent shareIntent = new Intent(Intent.ACTION_SEND);

shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
"Book Recommendation!");
shareIntent.putExtra(Intent.EXTRA_TEXT, mImageURL);

// Make sure the provider knows


// it should work with that Intent
mShareActionProvider.setShareIntent(shareIntent);

This should look very familiar, as it is nearly the same as the method added to MainActivity
earlier. The only difference is the use of mImageURL as the text to be shared.
Note: Some share service providers, like Facebook, will intelligently interpret the URL as an
image and display it to the users friends. Others, like e-mail, will simply include the link. Either
way, youre enabling your users to share dynamic content about a book they think others might
enjoy!
One final thing left to do adding the share button to the Action Bar. You can again reuse code
from MainActivity. Add this method to DetailActivity.java:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu
// this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
// Access the Share Item defined in menu XML
MenuItem shareItem = menu.findItem(R.id.menu_item_share);
// Access the object responsible for
// putting together the sharing submenu
if (shareItem != null) {
mShareActionProvider
= (ShareActionProvider)
MenuItemCompat.getActionProvider(shareItem);
}
setShareIntent();
}

return true;

Here, you could potentially use different menu XML files to populate the Action Bar on different
screens/activities. But for your purposes, the same menu/menu_main.xml file will do.
Build and run your app, and youll have a pretty powerful app! Your app now takes in your
search query, returns a list of books,allows you to take a closer look at a book cover, and share
that cover image with friends!

Where to Go From Here?


Congratulations on putting together your app! This tutorial has introduced you to a variety of
Android capabilities and techniques, and I hope you feel comfortable with the basics of
development on the Android platform.
You can get the full source code for this app on GitHub or as a zip.
If youre looking for a few more challenges, how about trying some of these?

Add a contentDescription attribute to your ImageViews for accessibility. Heres an


explanation.

Display more details about the book in the Detail View, like more information about the
book or even the first few lines of the book.

Reposition some of the views to a different layout structure.

Investigate android:background and add background colors to your layouts and views.

Add a hashtag to the share text.

Thank you for following this tutorial series. Please leave any comments or questions below!
The Android robot is reproduced or modified from work created and shared by Google and used
according to terms described in the Creative Commons 3.0 Attribution License.

Anda mungkin juga menyukai