- 
                Notifications
    You must be signed in to change notification settings 
- Fork 2
Basic UI
Generate a basic UI project, learn how the pieces fit together and deploy it to the emulator.
If you have not already done so, launch Android Studio.
On this screen, click Start a new Android Studio project.
You will see a Create Android Project wizard.
Let's review the options on this page.
This is the visible name of your project. Think of it as the title of your app.
Here, we will use ReadingList as the name of our application.
This is the domain of the owner of the application. It's also visible to the end users in Google Play.
I'd recommend that you use a subdomain rather than your top-level domain.
In this example, we are using curriculum.aboutobjects.com.
This tells the IDE where to create a new directory for your project.
You will notice that the end of the path is automatically populated with the Application name and does not end in a slash.
For this project, you will need to tailor this entry to match your personal machine. Pick a directory where you want to store your files.
By default, and convention, this is the reverse of your company name. You will note that the application name is also appended as if it were a subdomain as well.
While you could edit this, it is not recommended. It's not only best practice, but expected for any professional application or library.
At the bottom you will see options for using C++ and/or Kotlin.
We will not be using C++ for this class.
Many Android applications are written in Java. If you do not select the Kotlin checkmark, the generated project will be a Java-based project instead. You can still use both within the project if you need/want. Google is pushing pretty hard that Android developers start using Kotlin, and in many cases it does remove a lot of boilerplate code. For the purposes of this class, we will be using Kotlin to reduce the amount of boilerplate code you will need to type.
Make sure Kotlin is checked.
Click Next.
On this screen, you are asked to choose which Android devices you application is designed for.
For each section, you can select whether a particular category is supported; and if so, at what API level.  For this class, we are not covering watches or TVs or cars - so only the first category, Phone and Tablet will be selected.
Inside of that category, we have to choose an API level. This relates directly to what you learned about Android Versioning in the last chapter.
By default, it selects API 16 and tells you that it will support 99.6% of Phone/Tablet devices.
If you recall, API 16 only accounted for 1.1% of the market. While you may want to support all devices (and some applications may need to), it is unlikely that many employers will want to spend the time/cost/resources on maintaining the application for that version. As mentioned earlier, APIs change. You will have sections of your code that only work on API 16-20, for example; thus increasing the maintenance cost.
For this class, let's change that selector to API 22.  As we discussed earlier, that was the first API level that had double-digit distribution.  When we do, we see that it still reaches 80.2% of the market.
These numbers change over time. You will need to work with your product owners to determine what the correct break-off point is for your own application.
For now, once Phone/Tablet is selected and set to API 22, click Next.
The next screen allows you to choose which type of Hello World to auto-generate.
We will choose the Empty Activity.  Click on it then click on Next.
On the final step of the wizard, you will be asked to configure you activity.
It is important to know that the options presented on this screen will be different depending on the type of project you asked it to generate.
This will be the name of the activity class that is used to launch your application.  It defaults to MainActivity (without the .kt or .java extension).
Many people don't bother changing it because it is the launching point of their app. Unfortunately, after a few major revisions, they introduce things like splash screens or seasonally change what the starting point should be. For that reason, I suggest that we name it for what it does rather than for where it is currently being called.
Let's call it BookListActivity to reflect that it will display a list of books.  This will auto-generate BookListActivity.kt for us.
You will notice that when you change it, the Layout Name changed automatically to match.
We will go over the auto-generated files here shortly, but this checkmark will allow the IDE to auto-generate a starting point for you. Make sure it is checked.
This is the name of the xml file that will be generated.  By default, the IDE will call it activity_ followed by the name of your activity.  Camel cases are replaced with underscores as the names are all lowercase.
It should be defaulting to activity_book_list, which in turn will auto-generate activity_book_list.xml.
This option specifies whether to use android.app.Activity or android.support.v7.app.AppCompatActivity (which itself will get replaced with androidx.appcompat.app.AppCompatActivity).  This option is due to a breaking change that was made long ago in the Android ecosystem, and yet another that occurred recently.  While you could technically use either one when only supporting newer APIs, you are going to find that many of the libraries assume that you are using the AppCompat version.  Make sure it is selected.
Click Finish.
NOTE: If you are checking this project into source control, as you should never check in any files that are specific to your machine; consider making sure the following are in your
.gitignore:
.idea/
*.iml
*.iws
local.properties
.gradle/
Before we dive in to what was generated, let's take a brief look at the interface itself.
The largest portion of the screen is a tabbed editor. Through the settings, you can control how many tabs are visible, whether there are multiple lines of tabs, what color is used for text highlighting, et cetera.
Left of the editor is the project window. It will show the files in your project. The are some settings available on a tiny gear icon directly above it to control whether empty packages are hidden, among other useful features.
On the far left of the screen, left of the project window, you will see some sideways tabs. Those can be used to open additional tool windows onto that side view. You won't use those right now, but the Build Variants one is particularly useful when you start publishing your application.
Similar to those tabs, there are additional ones on the far right and far bottom of the screen. We will call them out as needed.
On the bottom of the screen, when you first opened your project, you will have noticed that the IDE automatically built your project.  For now, you can click the red X to dismiss that bottom window.  You might have to do it more than once.
Above the project and project window and the editor is the breadcrumb path. It will automatically update to show the path to the file currently visible in the editor.
At the very top of the page is the menu and toolbar. There are many options and settings in those. We will call those out as appropriate.
If you expand the files in your project window on the top left, you will see three main categories of files.
When you open each file, you will notice that the breadcrumb above the editor shows the file path; while the project window has them arranged by functionality.  For example, the AndroidManifest.xml is shown under app/manifests in the project window, but shows ReadingList/app/src/main/AndroidManifest.xml in the breadcrumb.
Let's take a look at each one.
As mentioned above, the AndroidManifest.xml is found in app/src/main.  If you end up having different variants of your application (like free vs pro, or debug vs release) you will likely have more than one.  Until that time though, the main directory will be used as the default.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.aboutobjects.curriculum.readinglist">
    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".BookListActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>The manifest/package is the unique identifier for your application.  It will show up in Google Play and in the Settings app for the end user.  It is also the key you would use to uninstall it from the command line.
Inside the manifest we have a single application tag.  It specifies some global defaults for our application and acts as the container for everything else.
Inside the application, we have our activity tag for the BookListActivity we created.  Note that the name starts with a period.  That indicates that you want it to inherit the package name above.  Alternatively, you could specify the fully qualified package name.
Inside the activity we have our intent-filter.  This tells the system how to launch our activity.  In this case, we are specifying that this particular activity is our MAIN LAUNCHER... ie: when someone runs our application, we expect this activity to be the one that starts.
Pay special attention to everything that starts with an at-symbol @.  Those indicate references to other files that we will discuss in a moment.
More information on this file can be found on the Android Developer site.
If you had not selected the Kotlin checkmark during the Create Android Project wizard, this would have instead been BookListActivity.java.  There would have been more lines of code, but the functionality would have been the same.
Even though the auto-generated files are Kotlin, note that they are included under app/src/main/java.  If you are inheriting an older codebase, you might see app/src/main/kotlin - but that is no longer the preferred convention.
package com.aboutobjects.curriculum.readinglist
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
class BookListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_book_list)
    }
}In the auto-generated Hello World, this class does not have much to it. It is using the name we specified in the wizard, extending the AppCompat version of the Activity (as we specified in the wizard) and displaying the auto-generated UI layout that we also specified in the wizard.
It is worth pointing out that while the XML file above used the @-style convention to reference other files (like @string/app_name), the Java or Kotlin code uses the R. programmatic convention to reference them (like R.layout.activity_book_list).  We will see more of this as we move on.
We will discuss Instrumentation Testing in another chapter.  For now, just note that the are included in the app/src/androidTest subdirectory.
package com.aboutobjects.curriculum.readinglist
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getTargetContext()
        assertEquals("com.aboutobjects.curriculum.readinglist", appContext.packageName)
    }
}Similarly, we will discuss Unit Testing in that same chapter.  For now, just note that the are included in the app/src/test subdirectory.
package com.aboutobjects.curriculum.readinglist
import org.junit.Test
import org.junit.Assert.*
/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }
}Android 8 (Oreo) introduced the concept of Adaptive Launcher Icons.
<?xml version="1.0" encoding="utf-8"?>
<vector
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:height="108dp"
        android:width="108dp"
        android:viewportHeight="108"
        android:viewportWidth="108">
    <path android:fillColor="#008577"
          android:pathData="M0,0h108v108h-108z"/>
    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
...clip...
    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>Creating these icons is beyond the scope of this tutorial, but there is a guide here on how to auto-generate them with Android Studio.
You will notice that this file is located in src/main/res/layout.  Barring variants, this is the directory where you will put most of your layouts.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".BookListActivity">
    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>A few things to point out here.
The xml namespaces at the top-level will almost always be included. If you forget them, the IDE will prompt you and auto-add them.
There can only be one top-level element, in this case a ConstraintLayout. Each type of layout has their own attributes and quirks. For example, a LinearLayout must specify an orientation, and a ScrollView can only have one child.
Here, we are specifying that the ConstraintLayout should match the parent height and width. If you start nesting layouts, you may need to know what kind of parent you are nesting into.
The TextView is set to take up the minimal amount of required space to actually show itself (wrap_content) and to be centered (equidistant to each of the four sides).
For more information on ConstraintLayout, you can look at the API documentation.
These are the launcher icons for different screen sizes.
On the Android Developer site you can see a table that explains what each of these dpis are intended to represent, how calculations are performed and an example of the differences between the sizes.
For our purposes today, your icons were auto-generated by the IDE. When you are ready to make your own images it is recommended that you start with an SVG source and create adaptive icons as mentioned above.
While these are bundled with the PNGs, they just tell the system to use the adaptive icon files above.
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <background android:drawable="@drawable/ic_launcher_background"/>
    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>Note that the .xml extension is not included in the references.
Rather than hard-coding colors throughout your code, you can specify them in a single file and refer to them by name. That makes it easier to make global changes to your app (like, say, applying a holiday theme).
While this file is located in src/main/res/values it is possible to have different variants of your application use different color schemes just by having two different versions of this file.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>
</resources>These colors are represented by ARGB hex values. The colorPrimary is used for the bar at the top of your application as well as some other UI.  The colorPrimaryDark is used for the status bar, above your application bar as well as some contextual UI. The colorAccent is used for controls like text fields and checkboxes.
If you are unfamiliar with ARGB hex values, you can head over to W3C to help you pick colors.
In the same directory, you will find your strings.xml.  While it currently only contains one string, it will become a very important file for you.  Every time you consider hard-coding any text in your app, it probably should go in this file instead.
<resources>
    <string name="app_name">ReadingList</string>
</resources>Currently, it only contains the name of your application. You might remember that we encountered it before when we discussed the AndroidManifest:
android:label="@string/app_name"In this reference, the manifest specified that the label was the app_name entry in this strings.xml file.
If you go back and look at the manifest, you will see the icons were referenced in the same way.
The initial version of our styles.xml might seem a little confusing.
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>Why are we setting colorPrimary to itself, you may ask?
Actually, the Theme.AppCompat.Light.DarkActionBar theme has a colorPrimary property.  By default, it doesn't know what color you set in the colors.xml. You could have called it anything, maybe fred.  Here, you are assigning your chosen color to the property in the theme.
As we continue our lessons, we will re-visit this configuration file to control other parts of the UI styling. For now, it's enough to know that this is where it is done.
The Android project that was auto-generated is built using Gradle. It is not the only way to build Android projects, but it is the one we will focus on.
You will notice that there are two build.gradle files.  One says Project and one says Module.  You will have one for the top-level all-encompassing project, and one for every module in it.  Currently, we have one module.
The project-level build.gradle specifies anything that is common between all modules.  Since we only have one module, the most important thing is that it sets us to to do a build.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = '1.3.10'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        google()
        jcenter()
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}The first thing you will notice is that the file specifies two repositories, not once but twice. These repositories are generally Maven repositories that contain third party libraries. For example, take a look at jcenter mentioned above.
But, why is it listed twice?
The first one, inside the buildscript closure, allows the build tools to resolve their own dependencies.
The second one, inside the allprojects closure, allows your modules to resolve their dependencies.
They do not have to have the same list.
The order in each list does, however, matter. Sometimes a dependency will show up in more than one repository. The first match will be the one that is used. The recommended approach is to list your internal repository first, if you have one, so that is can cache and proxy results reducing bandwidth, costs and time. In addition, you might want faster or more reliable repositories to be higher on the list.
The other thing you might notice about this file is that it specifies the version of the com.android.tools.build:gradle and org.jetbrains.kotlin:kotlin-gradle-plugin dependencies.  In this case, we have specified that we will use the Android Gradle plugin 3.2.1 and the Kotlin Gradle plugin 1.3.10.
While you can specify Gradle dependencies as Group, Artifact and Version; they are almost always specified as a single string in the form "Group:Artifact:Version"
The module-level build.gradle controls the building for the specific module, in this case named 'app'. While not very creative, it is the default name given to application projects created by the IDE.
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.aboutobjects.curriculum.readinglist"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}Let's walk through this one.
The first line does apply plugin: 'com.android.application' which tells the build system that we are building an Android application. Not a middleware library, not a Java webservice, et cetera.  This in turn adds additional functionality and steps to the build.
The next two plugins, kotlin-android and kotlin-android-extensions enable the use of Kotlin in the build.
After that we have two closures, android and dependencies.
In the android closure, we specify the compileSdkVersion.  This is the version of the Android API level we are using to compile and MUST be installed in the SDK Manager.  You should strive to make this the latest version at all times as it will help you catch problems early.
Inside the defaultConfig closure, we specify our applicationId which matches our packageName in the AndroidManifest.
The minSdkVersion is the minimum API level that we support.  During the Create Project Wizard, we changed this from 16 to 22.
The targetSdkVersion is the highest API level your application will support.  Specifically, code blocks in the framework will check this to determine whether to change behavior.
Having compileSdkVersion higher than targetSdkVersion will allow you to start working towards support for new features before enabling them.
For a larger discussion on compileSdkVersion/minSdkVersion/targetSdkVersion, please see this article by Ian Lake from Google.
versionCode is an ever-increasing number whereas versionName is a human-readable version.  The versionName is what shows up in Google Play to the end user.  You can think of versionCode as more of a uniqueKey, where the newest one always has to be higher than the last.
You might be asking yourself what to use for the versionName.  Should it be '1.0' or '1.2.3' or something else entirely.  There are some unique version schemes out there. TeX, for example, uses ever increasing digits of pi for their versioning.  By far, the most common and recommended version scheme is semantic versioning.
The testInstrumentationRunner just specifies how we will run unit tests and can be ignored for now.
Under the buildTypes closure, you can see there is a release closure. It specifies that we will use the Proguard file mentioned below.  In general, we never obfuscate when doing debug builds.
In the dependencies closure at the bottom, we see a list of implementation lines, a testImplementation line and two androidTestImplementation lines.  The testImplementation is a dependency for the unit test we saw earlier in the src/main/test directory.  The androidTestImplementation are dependencies for the instrumentation tests we saw earlier in the src/main/androidTest directory.
Of the other implementation dependencies, it is important to call out the first one.
implementation fileTree(dir: 'libs', include: ['*.jar'])This line allows .jar files inside the libs directory to be treated as dependencies.  Note that it does not work for .aar and does not handle transitive dependencies.
This is a really bad idea. You should never check these files into source control. They belong in an internal repository instead. You can get a free open-source version of Nexus here written by the company that wrote the O'Reilly book. You can run it locally or in the cloud - but I would recommend having one for your organization, as discussed in the project-level
build.gradlesection.
Whenever I create a new project, I usually delete that line as soon as possible to discourage it's use.
This file is checked into source control and is used to further configure the build.
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=officialBy default, it doesn't have much in it. You might add things to it like specifying where to find some config file or keystore.
This file tells Gradle what version to install and run.
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/distsMost people just change the 4.6 above to whatever version they want to use and rebuild, but it is possible to configure it via a closure inside the project-level build.gradle.
When you go to release your application, you will need to tell Proguard which files/methods/variables to NOT obfuscate.
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFileWhile outside the scope of this course, Google has posted a YouTube video from Google I/O 2018.
This file will seem a little silly at first.
include ':app'If you have multiple modules that you want to build, you would list them all here on a comma-separated line.
For more extensive use of this file, see the Gradle documentation.
Unlike the gradle.properties, this file should NOT be checked into source control. This file is specific to the machine it is running on. How your machine is setup may not be the same as mine. Not only might we have different applications, directories or memory requirements - we may not even be on the same operating system. This file allows us to do machine-specific tweaking.
For example, on my machine, it auto-generated this:
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Tue Nov 13 14:29:55 PST 2018
ndk.dir=/usr/local/android-sdk/ndk-bundle
sdk.dir=/usr/local/android-sdkWhat did yours generate?
Android developers will often deploy the application they are developing to their own device. Sometimes that requires extra device drivers, extra udev rules, OEM software, et cetera.
The other common option is to deploy to an Android Emulator. While these tend to take more computing resources than attaching your own device, they are often simpler to get working. We will use an emulator for the rest of this course.
If you later wish to try with your own devices, please see this page to get information on how to do so for your platform.
We will start by launching the AVD Manager in the toolbar under Tools.
On the Android Virtual Device Manager dialog, you will see a list of any virtual devices you have already configured.
On the bottom left, click on Create Virtual Device...
This specifies the type of device you are going to create.  They currently do not show Android Auto or Android Things on that list.  Select Phone.
The center of the screen shows a list of device specifications. You can search the list, add new ones, etc.
For now, let's select the 420dpi Pixel 2 that shows it has Play Store support, and click Next.
On the next screen, you are asked to select a system image.
Google shows you the recommended system images - and they may be different on your platform than they are on mine.
One thing I have noticed is that even though x86_64 (64-bit) may be supported and shown under the x86 tab, it doesn't necessarily show under the Recommended tab. This is unfortunate since the x86_64 images will perform better on platforms that support it.
If your system is not an x86 platform, the x86 images do not add any performance benefit to you.
Select a Pie/API Level 28/Android 9.0 (Google Play) option available to you.  If you wish to select the x86 Images tab to find one that is x86_64 you may do so - just make sure the rest of the options match.
Note that there is a difference between
(Google Play)and(Google APIs)
When you have chosen the one you want, click the Download link, if available.  This step takes awhile.
If you have previously downloaded this system image, you will skip this step.
When it is done, click Finish and re-select the newly installed system image.
Click Next.
Now you can configure your new emulator.
We want something descriptive. If you end up making multiple emulators to test customer experience, you don't want to have to guess which is which.
Name it Pixel 2 API 28 Google Play
Take note that just below the name it tells you the screen dimensions. For us, we can see that this emulator will be a 5" display, 1080 pixels wide, 1920 pixels high and have a screen density in the xxhdpi bucket that we discussed earlier.
This really matters more to tablets. The native orientation for some tablets is landscape and for others portrait. The reason this matters is that a lot of routines assume 90° rotation is landscape - but that is not always the case.
Leave it at Portrait.
This option doesn't matter much, but will make your experience with the emulator better. Leave it enabled.
Click the Show Advanced Settings.
We are not going to change the Camera or Network settings here, but feel free to look at them.
This is a tricky one. The default setting is to Quick Boot, which, in theory, makes the emulator boot up faster.
Unfortunately, it often prevents the emulator from booting at all.  For the duration of this class, set it to Cold Boot.  We would rather it start up correctly than take a few seconds less.
It is very possible you will change these options when working on your own application. You may create custom emulators with low memory or really large storage to test different scenarios.
For now, leave them at the defaults.
When it works, the keyboard input can make your life much easier. It allows you to use your computer keyboard to enter text on the emulator rather than using the mouse with the virtual keyboard. Sometimes it doesn't work -- but leave it enabled and hope for the best.
Once you are satisfied with everything, click Finish.
You should now see your new Pixel 2 API 28 Google Play AVD listed.
By default, if the emulator is not running, the build can start the emulator when it deploys your application. Once you are done testing, it can then shut your emulator down again.
Rather than waste a lot of time doing that, it's much convenient to start the emulator once and leave it running. If your machine has low memory, that may not be an option - but we will try it now so that you know how to do it.
On the line containing your new emulator, click the play button on the far right next to the edit pencil.
With your emulator now running, you can close the AVD manager and continue to use the emulator and IDE at the same time.
So what's the first thing we want to do with our new emulator? How about deploy our auto-generated project?
Back in the IDE, look at the toolbar.
Next to the selector that says app you will see a green play button.  Click it.
You will be prompted to select which device you would like to deploy your application to.
If the emulator is still running, it will show up as a Connected Device.
If you have a connected Android device (with proper udev and/or drivers), it will also show up as a Connected Device.
If neither of those are the case, your emulator will show up under Available Virtual Devices.  In this case, it will start the emulator in order to deploy to it.
Select Pixel 2 API 28 Google Play and click OK.
Now that we have seen our Hello World, let's go ahead and stop it.
Back in the IDE, click on the red stop button in the toolbar.
You might notice the lightning bolt that wasn't there before. That allows us to update the running application without stopping it first. We're not ready for that yet.
Next, we will tweak a few of the files we looked at earlier to understand how they impact your application.
We're going to start with the Layout.  Open your app/res/layout/activity_book_list.xml in the editor.
As mentioned above, it currently looks like
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".BookListActivity">
    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>Let's make a couple small changes to it.
The ConstraintLayout represents the background container of this page of our application. Right now, that is a stark white background. Let's soften it a little.
In between the android:layout_height and tools:context parameters, let's add a new background color.
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff8dc"
        tools:context=".BookListActivity">The hex value fff8dc represents the HTML color cornsilk.
Once you have made that change, redeploy your application and check the results.
The background isn't as bright now, but the text is a bit harder to see.
Inside the TextView tag, after the android:text="Hello World!" line, hit enter to create a new line. Type in android: and notice that you are prompted with the avaialble properties.  Choose the textStyle one and notice that you are now prompted with the possible values.  Choose bold.
It should now look like
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>Deploy your application and see the results.
It's a little better, but can we make the text larger?
In the same way that you did textStyle, add a textSize.
Note that this time it only prompted you with an @android value.  Here we will have to improvise.  Use 24sp as the value.
You might recall from earlier that we discussed different screen densities?
When we are specifying sizes in Android, we never use pixel values; which can seem counter-intuitive. Instead, Android uses something call
dpor Device-Independent Pixels to represent a similar UI size, regardless of the phone screen size. Similarly, Android also usessp, or Scalable Pixels for text specifically so that the text size also changes if the user modifies their accessibility settings.Long story short, use
dpfor layouts andspfor text.For more information on screen densities, see the Android Developer site.
You should have added:
android:textSize="24sp"Deploy your application and see the results.
Let's start by grabbing a public domain image and saving it locally.  Download this image and save it into your app/src/main/res/drawable/ folder as earth.png. Remember that Android is case-sensitive.
Below the TextView, but still inside the ConstraintLayout (remember that we can only have one top-level container), start typing <Ima and choose ImageView.  When prompted for the sizing, choose wrap_content for both the width and the height.
Here's what we have so far.
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />Add another attribute to the ImageView. As you type android: you will see src as an option. Select that and you will see @drawable/earth as an option.  That is the image you just saved.  Select it.
If you deploy your application now, what do you see?
The Earth shows up, but it takes the whole screen. Where is your text?
If you look at your TextView, you will see that it is constrained to all edges of the parent.  What about the ImageView?  It has no constraints, so it is overlapping it and taking over the whole screen.  You can see this by clicking on the Design tab at the bottom of the screen in the IDE.
Go back to the Text view and let's fix it.
Let's start by copying the 4 constraints from the TextView into the ImageView.
Next, we'll want to tell the TextView to be above the ImageView; and tell the ImageView to be below the TextView. To do this, we need to give them each an identifier.
In the TextView, add an attribute android:id="@+id/hello_text".  In the ImageView, add android:id="@+id/earth_image".
Now we can specify relationships between them.
In the TextView, replace app:layout_constraintBottom_toBottomOf="parent" with app:layout_constraintBottom_toTopOf="@+id/earth_image".
In the ImageView, replace app:layout_constraintTop_toTopOf="parent" with app:layout_constraintTop_toBottomOf="@+id/hello_text"
End result is something like this
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff8dc"
        tools:context=".BookListActivity">
    <TextView
        android:id="@+id/hello_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textStyle="bold"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/earth_image"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <ImageView
        android:id="@+id/earth_image"
        android:src="@drawable/earth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/hello_text" />
</android.support.constraint.ConstraintLayout>Take a look at the Design tab and you should see that "Hello World" is now above the image. Switch back to the Text tab.
Deploy your application.
Keep your activity_book_list.xml and open app/res/values/strings.xml next to it.
You might remember that we discussed earlier that we should avoid hardcoding values where possible?  In our layout, we are currently hardcoding the text "Hello World!".  Let's move that to our strings.xml.
In your strings.xml file, in between the two resources tags (remember, one top-level container), let's add another <string tag like the one used for your app_name.  Let's call this one hello.  When you type <st it will prompt you to complete it as a string.  If you do so, it will put the caret inside the quotes for you to type hello.  You will notice that it is surrounded by a red box.  Hit the tab character on your keyboard to tell it you are done, then type > for it to auto-complete the end-tag.  It's now expecting you to enter the value.  You can type it or copy it from the layout.
<resources>
    <string name="app_name">ReadingList</string>
    <string name="hello">Hello World!</string>
</resources>To tell the layout to use this new string resource, replace android:text="Hello World!" with android:text="@string/hello".  You will notice that auto-completion is there as well.
You might be asking - aren't we still hardcoding it? We are, but you can provide variations of this file for different versions of your application, different languages, different countries, et cetera -- without needing to change any code or layouts.
Deploy your application to make sure it is still working.
Still looks OK, but how can we be sure?
Let's change the text in the strings.xml.
<resources>
    <string name="app_name">ReadingList</string>
    <string name="hello">Hello, Earth!</string>
</resources>Re-deploy and verify.
Any time you writing hard-coded text in an layout or source file, consider putting it inside the
strings.xmlinstead.
Similarly, we should not be hardcoding hex color values anywhere. Let's fix that.
Open your layout file and your colors.xml file.
We are going to replace the background color in the ConstraintLayout with an @color reference, the same way we did with the strings.
Before continuing, see if you can figure it out.  Remember that the hex value we used was for the color cornsilk.
As a reminder, you can always use the W3C to match up hex color values with common names.
Were you able to figure it out?
Inside the colors.xml file, we add a new color tag with our hex value and name.
<color name="cornsilk">#fff8dc</color>Inside our layout, we replace our hardcoded value android:background="#fff8dc" with the new color reference android:background="@color/cornsilk".
This same pattern is used through most of Androids' resources.
Deploy the application and verify that everything still looks the same.
Of course, we want to make sure there was a change...
Android has some built-in colors you can reference.  You can reference them with @android:color/ instead of just @color/.  Let's try that now.  Change the ConstraintLayout background to @android:color/black.
Redeploy.
The background changed, but now you can't see your text.
In the TextView, add a new attribute.  Let's use your newly defined cornsilk for the text. android:textColor="@color/cornsilk".
Redeploy.
When you start having multiple layouts doing the same thing over and over, you will start realizing that even the styling of those layouts can feel like hardcoding. That's especially true if you are always setting the same text size, color, styling, font, etc... on every single text view.
To combat that, we follow the same pattern that we just learned about and move settings into styles.
Let's look at your layout file and your styles.xml.
Styles are a little different in that they often specify a parent that they are inheriting from. We won't worry about that for now, and will address it as it comes up.
For now, let's move the styling for our TextView.  You will want a unique name that specifies what it is and would make sense across the entire application.  For now, we will call it LightTitle.
Inside the styles.xml file, inside the main resources tag, we will add another style tag named LightTitle, with no parent.
So far, you should have this:
<style name="LightTitle">
    
</style>It is somewhat arbitrary what should be in the layout and what should be in the style. Each team might have their own policies. To keep it simple, we will assume styling goes in styles and laying out goes in the layout.
Looking at our current TextView, we have
<TextView
    android:id="@+id/hello_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    android:textStyle="bold"
    android:textSize="24sp"
    android:textColor="@color/cornsilk"
    app:layout_constraintBottom_toTopOf="@+id/earth_image"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>- The idmust stay at the layout.
- The textis specific to this instance, so should stay.
- The layout_constraint*are specific to how it is positioned on the screen, so that should stay.
- The textStyleis a generic style for our LightTitle, so should be moved.
- The textSizeis should also move.
- If our style was just Title, we could justify keeping thetextColorin the layout. Since we are calling itLightStyle, then the intention is to include the color as well. We will move it.
- What about the layout_widthandlayout_height. This one is an interesting one. On one hand you could argue that LightTitle should (or should not) take up the entire width of the screen, as a matter of styling. On the other hand, it has the word layout right in the attribute. This is one that developers often disagree about. We often tend to put it into the styles because we copy/paste it everywhere; but it is specific to the type of layout that holds it. We'll leave them for now.
Ok, so let's move textStyle, textSize and textColor.
In your new style, add the following attributes to match what we already have in the layout:
<style name="LightTitle">
    <item name="android:textStyle">bold</item>
    <item name="android:textSize">24sp</item>
    <item name="android:textColor">@color/cornsilk</item>
</style>The name of each item matches the parameter name in the layout. The values are the same, but without the wrapping quotes.
In your layout, add style="@style/LightTitle" to your TextView then remove the textStyle, textSize and textColor attributes.
Save and redeploy.
Ok, everything should still be working. Anytime you want to make a title with those three parameters, you can just specify the style instead.
Let's talk about the style parents.
Remember how we said that the textColor was the only reason our style was a LightTitle?
Add a new style above it called MyTitle (creative, right?).
Move the textSize and textStyle from LightTitle to MyTitle.
Now, add parent="MyTitle" to LightTitle.
End result should look something like
<style name="MyTitle">
    <item name="android:textStyle">bold</item>
    <item name="android:textSize">24sp</item>
</style>
<style name="LightTitle" parent="MyTitle">
    <item name="android:textColor">@color/cornsilk</item>
</style>You now have two styles. One generic title style, and one specifically light colored.  The LightTitle inherits the attributes from MyTitle.  In this way you can organize your styles so that a simple change has application-wide impact.
Redeploy your application and confirm everything is still working.






















