Mastering Android Development with Kotlin

4.5 (13 reviews total)
By Miloš Vasić
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Starting with Android

About this book

Kotlin is a programming language intended to be a better Java, and it's designed to be usable and readable across large teams with different levels of knowledge. As a language, it helps developers build amazing Android applications in an easy and effective way.

This book begins by giving you a strong grasp of Kotlin’s features in the context of Android development and its APIs. Moving on, you’ll take steps toward building stunning applications for Android. The book will show you how to set up the environment, and the difficulty level will grow steadily with the applications covered in the upcoming chapters.

Later on, the book will introduce you to the Android Studio IDE, which plays an integral role in Android development. We’ll use Kotlin’s basic programming concepts such as functions, lambdas, properties, object-oriented code, safety aspects, type parameterization, testing, and concurrency, which will guide you through writing Kotlin code into production. We’ll also show you how to integrate Kotlin into any existing Android project.

Publication date:
November 2017
Publisher
Packt
Pages
378
ISBN
9781788473699

 

Chapter 1. Starting with Android

Kotlin has been officially announced by Google as a first-class programming language for Android. Find out why Kotlin is the best tool available for you as a newcomer and why senior Android developers first adopted Kotlin.

In this chapter, you will learn how to set up a working environment. You will install and run Android Studio and set up Android SDK and Kotlin. Here, you will also be introduced to some important and useful tools such as Android Debug Bridge (adb).

Since you don't have your project yet, you will set it up. You will initialize a Git repository to track changes in your code and create an empty project. You will enable it to support Kotlin and add support for additional libraries that we will use.

After we have initialized the repository and project, we will go through the project structure and explain each file the IDE has generated. Finally, you will create your first screen and take a look at it.

This chapter will cover the following points:

  • Setting up an environment for the development of Git and Gradle basics
  • Working with Android Manifest
  • Android emulator
  • Android tools
 

Why Kotlin?


Before we start our journey, we will answer the question from the chapter title--Why Kotlin? Kotlin is a new programming language developed by JetBrains, the company that developed IntelliJ IDEA. Kotlin is concise and understandable, and it compiles everything to bytecode just like Java. It can also compile to JavaScript or native!

Kotlin comes from professionals of the industry and solves problems programmers are facing every day. It is easy to start and adopt! IntelliJ comes with a Java to Kotlin converter tool. You can convert Java code file by file and everything will still work flawlessly.

It is interoperable and can use any existing Java Framework or library. The interoperability is impeccable and does not require wrappers or adapter layers. Kotlin supports build systems such as Gradle, Maven, Kobalt, Ant, and Griffon with external support.

The most important thing about Kotlin, for us, is that it works perfectly with Android.

Some of the most impressive Kotlin features are as follows:

  • Null safety
  • Exceptions are unchecked
  • Type inference works everywhere
  • One-liner functions take one line
  • Generated getters and setter out of the box
  • We can define functions outside of classes
  • Data classes
  • Functional programming support
  • Extension functions
  • Kotlin uses Markdown instead of HTML for API documents! The Dokka tool, a Javadoc alternative, can read Kotlin and Java source code and generate combined docs
  • Kotlin has a better generics support than Java
  • Reliable and performant concurrent programming
  • String patterns
  • Named method arguments
 

Kotlin for Android - it's official


On May 17th 2017, Google announced that it's making Kotlin, a statically typed programming language for the Java Virtual Machine, a first-class language to write Android apps.

The next version of Android Studio (3.0, current one is 2.3.3) will support Kotlin out of the box. Google will put its effort in the future of Kotlin.

Note

It is important to note that this is only an additional language, not a replacement for existing Java and C++ support (for now).

 

Downloading and configuring Android Studio


To develop our application, we will need some tools. First of all, we will need an IDE. For that purpose, we will use Android Studio. Android Studio provides the fastest tools to build apps on every type of Android device.

Android Studio offers professional code editing, debugging, and performance tooling. It's a flexible build system that allows you to focus on building a top quality application.

Setting up Android Studio takes just a few clicks. Before we go any further, you need to download the following version for your operating system:

https://developer.android.com/studio/index.html

Here are the instructions for macOS, Linux, and Windows:

macOS: To install it on macOS, follow these steps:

  1. Launch the Android Studio DMG file.
  2. Drag and drop Android Studio into the Applications folder.
  3. Launch Android Studio.
  4. Select whether you want to import previous Android Studio settings.
  5. Click on OK.
  6. Follow the instructions until Android Studio is ready for use.

Linux:To install it on Linux, follow these steps:

  1. Unpack the archive you downloaded to an appropriate location for your applications.
  2. Navigate to bin/directory/.
  3. Execute /studio.sh.
  4. Select whether you want to import previous Android Studio settings or not.
  5. Click on OK.
  6. Follow the instructions until Android Studio is ready for use.
  7. Optionally, select Tools | Create Desktop Entry from the menu bar.

Note

If you are running a 64-bit version of Ubuntu, you need to install some 32-bit libraries with the following command:sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386 In case you are running a 64-bit Fedora, the command is follows:sudo yum install zlib.i686 ncurses-libs.i686 bzip2-libs.i686

Windows:To install it on Windows, follow these steps:

  1. Execute the .exe file you downloaded.
  2. Follow the instructions until Android Studio is ready for use.
 

Setting up Android emulators


Android SDK comes with emulators capable of running applications we develop. We will need it for our project! The purpose of an emulator is to simulate a device and displays all its activity windowed on your computer. What can we do with it? We can prototype, develop, and test--all this without a hardware device. You can emulate phones, tablets, wearables, and TV devices. You can create your own device definitions, or you can use predefined emulators.

The good thing about emulators is that they are fast. In many situations, it will take less time to run an application on an emulator instance than on a real hardware device.

Working with the emulators is just as easy with a real hardware device. For gestures, you use your mouse, and for input, your keyboard.

Emulators can do anything a real phone does! You can easily send incoming phone calls and text messages! You can specify the location of the device, send fingerprint scans, adjust network speed and status, or even simulate battery properties. Emulators can have a virtual SD card and internal data storage, both of them you can use to send real files to that space.

Android Virtual Device (AVD) configuration is used to define an emulator. Each AVD instance works as a completely independent device! For the purpose of creating and management of AVDs, we use the AVD Manager. An AVD definition holds a hardware profile, system image, storage area, skin, and other important properties.

Let's play with it! To run the AVD Manager, do one of the following:

Select Tools | Android | AVDManager or click on the AVDManager icon in the toolbar:

 

It displays all AVDs you've already defined. As you can see, we don't have any yet!

What can we do here? We can do the following:

  • Create a new AVD
  • Edit an existing AVD
  • Delete the existing AVD
  • Create hardware profiles
  • Edit an existing hardware profile
  • Delete an existing hardware profile
  • Import/export definitions
  • Start or stop the AVD
  • Clear data and reset the AVD
  • Access the AVD .ini and .img files on the filesystem
  • View the AVD configuration details

To obtain the AVD instance, you can either create a new AVD from the beginning or duplicate an existing AVD and modify it by need.

Creating a new AVD instance

From the Your Virtual Devices of the AVD Manager, click on Create Virtual Device (you can do the same as you run your app from within Android Studio by clicking on the Run icon, and then, in the Select Deployment Target dialog, choose Create New Emulator). Please refer to the following screenshot:

Select a hardware profile and then click on Next, as shown in the previous screenshot.

If you notice the Download link next to the system image, you have to click on it. The download process starts, as you can see in the following screenshot:

We must note that the API level of the target device is very important! Your application can't run on a system image whose API level is less than the one required by your application. That attribute is specified in your Gradle configuration. We will deal with Gradle in detail later.

Finally, Verify Configuration appears:

Change the AVD properties if needed and then click on Finish to complete the wizard. The newly created AVD appears in the Your Virtual Devices list or the Select Deployment Target dialog, depending on where you accessed the wizard from.

If you need to create a copy of the existing AVD, follow these instructions:

  1. Open AVD Manager, right-click on the AVD instance, and select Duplicate.
  2. Follow the wizard, and, after you modified what you needed, click on Finish.
  3. A new modified version appears in our AVD list.

We will demonstrate dealing with hardware profiles by creating a new one from scratch. To create a new hardware profile, follow these instructions. In Select Hardware, click on New Hardware Profile. Please refer to the following screenshot:

Configure Hardware Profile appears. Adjust the hardware profile properties as needed. Click on Finish. Your newly created hardware profile appears.

Duplicating an existing AVD and modifying it by need

If you need a hardware profile based on an existing one, follow these instructions:

  1. Select an existing hardware profile and click on Clone Device.
  2. Update the hardware profile properties by your needs. To complete the wizard, click on Finish.
  3. Your profile appears in the hardware profile list.

Let's go back to the AVD list. Here, you can perform the following operations on any existing AVD:

  • Edit it by clicking on Edit
  • Delete by right-clicking and choosing Delete
  • Access the .ini and .img files on the disk by right-clicking on an AVD instance and choosing Show on Disk
  • To view the AVD configuration details, right-click on an AVD instance and choose View Details

Since we covered this, let's go back to the hardware profile list. Here, we can do the following:

  • Edit a hardware profile by selecting it and choosing Edit Device
  • Delete a hardware profile by right-clicking on it and choosing Delete

Note

You can't edit or delete the predefined hardware profiles!

Then, we can run or stop an emulator or clear its data as follows:

  • To run an emulator that uses an AVD, double-click on the AVD or just choose Launch
  • To stop it, right-click on it and choose Stop
  • To clear the data for an emulator, and return it to the same state as when it was first defined, right-click on an AVD and choose Wipe Data

We will continue our emulators' journey with the explanation of command-line features that you can use with *-.

To start an emulator, use the emulator command. We will show you some basic command-line syntax to start a virtual device from a terminal:

emulator -avd avd_name [ {-option [value]} ... ]

Another command-line syntax is as follows:

emulator @avd_name [ {-option [value]} ... ]

Let's take a look at the following example:

$ /Users/vasic/Library/Android/sdk/tools/emulator -avd Nexus_5X_API_23 -netdelay none -netspeed full

You can specify startup options when you start the emulator; later, you can't set these options.

If you need a list of available AVDs, use this command:

emulator -list-avds

The result is a list of AVD names from the Android home directory. You can override the default home directory by setting the ANDROID_SDK_HOME environment variable.

Stopping an emulator is simple--just close its window.

Note

It is important to note that we can run AVDs from Android Studio UI as well!

 

Android Debug Bridge


To access devices, you will use the adb command executed from the terminal. We will take a look into the common cases.

Listing all devices:

adb devices

Console output:

List of devices attachedemulator-5554 attachedemulator-5555 attached

Obtaining shell access to device:

adb shell

Accessing a specific device instance:

adb -s emulator-5554 shell

Where -s represents device source.

Copying a file from and to a device:

adb pull /sdcard/images ~/imagesadb push ~/images /sdcard/images

Uninstalling an application:

adb uninstall <package.name>

One of the greatest features of adb is that you can access it through telnet. Use telnet localhost 5554 to connect to your emulator device. Terminate your session using the quit or exit command.

Let's play with adb:

  • Connect to device:
telnet localhost 5554
  • Change the power level:
power status fullpower status charging
  • Or simulate a call:
gsm call 223344556677
  • Send an SMS:
sms send 223344556677 Android rocks
  • Set geolocation:
geo fix 22 22

Note

With adb, you can also take a screenshot or record a video!

 

Other important tools


We will cover some other tools you will need in everyday Android development.

Let's start with the following:

  • adb dumpsys: To get information about a system and running an application, use the adb dumpsys command. To get a memory status, execute the following command--adb shell dumpsys meminfo <package.name>.

Next important tool is as follows:

  • adb shell procrank: The adb shell procrank lists all the applications for you in the order of their memory consumption. This command does not work on live devices; you connect only with emulators. For the same purpose, you can use--adb shell dumpsys meminfo.
  • For battery consumption, you can use--adb shell dumpsys batterystats--charged <package-name>.
  • Next important tool is Systrace. To analyze performance of your application by capturing and displaying execution times, you will use this command.

When you have problems with application glitches, Systrace tool comes as a powerful ally!

It does not work with Android SDK Tools less than 20! To use it, you must have Python installed and configured.

Let's try it!

To access it from UI, open Android Device Monitor in Android Studio and then choose Monitor:

Sometimes, it can be easier to access it from the terminal (command line):

Note

The Systrace tool has different command-line options, depending on the Android version running on your device.

Let's take a look at some examples:

General usage:

$ python systrace.py [options] [category1] [category2] ... [categoryN]
  • Android 4.3 and up:
$ python systrace.py --time=15 -o my_trace_001.html 
        sched gfx  view wm
  • Android 4.2 and lower options:
$ python systrace.py --set-tags gfx,view,wm$ adb shell stop$ adb shell start$ python systrace.py --disk --time=15 -o my_trace_001.html

The last important tool we want to present is sdkmanager. It allows you to view, install, update, and uninstall packages for the Android SDK. It is located in android_sdk/tools/bin/.

Let's take a look at some common examples of use:

Listing installed and available packages:

sdkmanager --list [options]
  • Installing packages:
sdkmanager packages [options]

You can send packages you got from --list command.

  • Uninstalling:
sdkmanager --uninstall packages [options]
  • Updating:
sdkmanager --update [options]

There are also some other tools you can use in Android, but we only showed the most important ones.

 

Initializing a Git repository


We have installed Android Studio and introduced ourselves to some important SDK tools. We also learned how to deal with emulated devices that will run our code. It is time to start working on our project. We will develop a small application for notes and todos. This is a tool that everybody needs. We will give it a name--Journaler and it will be an application capable of creating notes and todos with reminders that will be synced to our backend.

First step in development is initializing a Git repository. Git will be our code versioning system. It is up to you to decide if you will use GitHub, BitBucket, or something else for a remote Git instance. Create your remote repository and keep its URL ready, along with your credentials. So, let's start!

Go into the directory containing the project:

Execute: git init .

The console output will be something like this:

Initialized empty Git repository in <directory_you_choose/.git>

We initialized the repo.

Let's add the first file--vi notes.txt.

Populate notes.txt with some content and save it.

Execute git add . to add all of the relevant files.

  • Then: git commit -m "Journaler: First commit"

The console output will be something like this:

[master (root-commit) 5e98ea4]  Journaler: First commit1 file changed, 1 insertion(+)create mode 100644 notes.txt

As you remember, you prepared your remote Git repository url with credentials. Copy url into a clipboard. Now, execute the following:

git remote add origin <repository_url>

This sets the new remote.

  • Then: git remote -v

This verifies the new remote URL.

  • Finally, push everything we have to remote: git push -u origin master

If you are asked for credentials, enter it and confirm by pressing Enter.

 

Creating an Android project


We initialized our code repository. It is time to create a project. Start Android Studio and choose the following:

Start a new Android Studio Project or File | New | New Project.

Create New Project and a window appears.

Fill the application information:

Then, click on Next.

Check the Phone and Tablet option, and then choose Android 5.0 as the minimum Android version as follows:

Click on Next again.

Choose Add No Activity and click on Finish, as follows:

Wait until your project is created.

You will notice a message about Unregistered VCS root detected. Click on add root or go to Preferences | Version Control | , and then select our Git repository from the list and the click on then + icon, as shown in the following screenshot:

To confirm everything, click on Apply and OK.

Before committing and pushing, update your .gitignore files. The purpose of the .gitignore file is to allow you to ignore files, such as editor backup files, build products, or local configuration overrides that you never want to commit into a repository. Without matching the .gitignore rules, these files will appear in the untracked files section of the Git status output.

Open .gitignore located in your project root directory and edit it. To access it, expand Project by clicking on Project on the left side of Android Studio, and then, from the drop-down menu, choose Project, as shown in the following screenshot:

Let's add some lines:

.idea.gradlebuild/gradle*!gradle-plugins*gradle-app.setting!gradle-wrapper.jar.gradletasknamecachelocal.propertiesgen

Then, edit .gitignore, which is located in the app module directory:

*.class.mtj.tmp/*.jar*.war*.earhs_err_pid*.idea/*.DS_Store.idea/shelf/android.tests.dependencies/confluence/target/dependencies/dist/gh-pages/ideaSDK/android-studio/sdkouttmpworkspace.xml*.versionsBackup/idea/testData/debugger/tinyApp/classes*/jps-plugin/testData/kannotatorultimate/.DS_Storeultimate/.idea/shelfultimate/dependenciesultimate/ideaSDKultimate/outultimate/tmpultimate/workspace.xmlultimate/*.versionsBackup.idea/workspace.xml.idea/tasks.xml.idea/dataSources.ids.idea/dataSources.xml.idea/dataSources.local.xml.idea/sqlDataSources.xml.idea/dynamic.xml.idea/uiDesigner.xml.idea/gradle.xml.idea/libraries.idea/mongoSettings.xml*.iws/out/.idea_modules/atlassian-ide-plugin.xmlcom_crashlytics_export_strings.xmlcrashlytics.propertiescrashlytics-build.propertiesfabric.propertiestarget/pom.xml.tagpom.xml.releaseBackuppom.xml.versionsBackuppom.xml.nextrelease.propertiesdependency-reduced-pom.xmlbuildNumber.properties.mvn/timing.properties!/.mvn/wrapper/maven-wrapper.jarsamples/*build/*.gradle/*!libs/*.jar!Releases/*.jarcredentials*.gradlegen

You can use this .gitignore configuration from the preceding. Now we can commit and push cmd + 9 on macOS or ctrl + 9 on Windows/Linux (shortcut for View | Tool Windows | Version Control). Expand unversioned files, select them, and right-click on Add to VCS.

Press Cmd + K (or Ctrl + K on Windows/Linux), check all files, enter commit message, and, from the Commit drop-down menu, choose Commit and Push. If you get Line Separators Warning, choose Fix and Commit. The Push Commits window will appear. Check Push Tags and choose Current Branch, and then Push.

 

Setting up Gradle


Gradle is a build system. You can build your Android application without one, but, in that case, you have to use several SDK tools by yourself. That is not simple! This is a part where you need a Gradle and Android Gradle plugin.

Gradle takes all the source files and processes them by tools we mentioned. Then, it packs everything into one compressed file with the .apk extension. APK can be uncompressed. If you rename it by changing its extension to .zip, you can extract the content.

Each build system uses its convention. The most important convention is about placing source code and assets in a proper directory with proper structure.

Gradle is a JVM-based build system, so that practically means that you can write your own script in Java, Groovy, Kotlin, and so on. Also, it's a plugin-based system and is easy to extend. One good example of it is Google's Android plugin. You probably noticed build.gradle files in your project. They are all written in Groovy, so any Groovy code you write will be executed. We will define our Gradle scripts to automate a building process. Let's set up our building! Open settings.gradle and take a look at it:

include ":App"    

This directive tells Gradle that it will build a module named App. The App module is located in the app directory of our project.

Now open build.gradle from project root and add the following lines:

    buildscript { 
      repositories { 
        jcenter() 
        mavenCentral() 
      } 
      dependencies { 
        classpath 'com.android.tools.build:gradle:2.3.3' 
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.3' 
      } 
    } 
 
    repositories { 
      jcenter() 
      mavenCentral() 
    } 

We defined that our build script will resolve its dependencies from JCenter and Maven Central repositories. The same repositories will be used to resolve project dependencies. Main dependencies are added to target each module we will have:

  • Android Gradle plugin
  • Kotlin Gradle plugin

After you updated the main build.gradle configuration, open build.gradle located in the App module directory and add the following lines:

    apply plugin: "com.android.application" 
    apply plugin: "kotlin-android" 
    apply plugin: "kotlin-android-extensions" 
    android { 
      compileSdkVersion 26 
      buildToolsVersion "25.0.3" 
      defaultConfig { 
        applicationId "com.journaler" 
        minSdkVersion 19 
        targetSdkVersion 26 
        versionCode 1 
        versionName "1.0" 
        testInstrumentationRunner  
        "android.support.test.runner.AndroidJUnitRunner" 
      }  
       buildTypes {     
         release {   
           minifyEnabled false    
           proguardFiles getDefaultProguardFile('proguard- 
           android.txt'), 'proguard-rules.pro'    
         }
       }    
       sourceSets {   
         main.java.srcDirs += 'src/main/kotlin'  
       }}
       repositories { 
         jcenter()  
         mavenCentral()
       }dependencies {
          compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.3"  
          compile 'com.android.support:design:26+'  
          compile 'com.android.support:appcompat-v7:26+'}

The configurations we set enable Kotlin as a development language for our project and Gradle scripts as well. Then, it defines a minimal and target sdk version that an application requires. In our case, this is 19 as minimum and 26 as target. It is important to note that in the default configuration section, we set application ID and version parameters too. The dependencies section sets dependencies for Kotlin itself and some Android UI components that will be explained later.

 

Explaining directory structure


Android Studio contains everything you need to build an application. It contains source code and assets. All directories are created by the wizard we used to create our project. To see it, open the Project window on the left side of the IDE (click on View | ToolWindows | Project), as shown in the following screenshot:

A project module represents a collection of source files, assets, and build settings that divide projects into discrete functionality parts. The minimal number of modules is one. There is no real limit on the maximal modules number your project can have. Modules can be built, tested, or debugged independently. As you saw, we defined the Journaler project with only one module named app.

To add a new module, following these steps:

Go to File | New | New Module.

It's possible to create the following modules:

  • Android Application Module represents a container for your application source code, resources, and settings. The default module name is app, like in our created example.
  • Phone & Tablet Module.
  • Android Wear Module.
  • Glass Module.
  • Android TV module.
  • Library module represents a container for reusable code--a library. The module can be used as a dependency in other application modules or imported into other projects. When it's built, the module has an AAR extension--Android Archive instead of having an APK extension.

The Create New Module window offers the following options:

  • Android Library: All types are supported in an Android project. The build result of this library is an Android Archiver (AAR).
  • Java Library: Only supports pure Java. The build result of this library is a Java Archiver (JAR).
  • Google Cloud Module: This defines a container for the Google Cloud backend code.

It is important to understand that Gradle refers to modules as individual projects. If your application code depends on the code for the Android library called Logger then in build.config, you use must include the following directive:

    dependencies { 
      compile project(':logger') 
    } 

Let's navigate through the project structure. The default view Android Studio uses to display your project files is Android view. It doesn't represent the actual file hierarchy on disk. It hides certain files or directories that are not often used.

Android view presents the following:

  • All the build-related configuration files
  • All manifest files
  • All other resource files in a single group

In each application, the module content is presented in these groups:

  • Manifests and AndroidManifest.xml files.
  • Java and Kotlin source code for application and tests.
  • The res and Android UI resources.
  • To see the real file structure of the project, choose Project view. To do this, click on Android view and, from the drop-down menu, choose Project.

By doing this, you will see a lot more files and directories. The most important of them are as follows:

  • module-name/: This is the name of the module
  • build/: This holds build outputs
  • libs/: This holds private libraries
  • src/: This holds all code and resource files for the module organized in the following subdirectories:
    • main: This holds the main source set files--source code and resources shared by all build variants (we will explain build variants later)
    • AndroidManifest.xml: This defines the nature of our application and each of its components
    • java: This holds the Java source code
    • kotlin: This holds the Kotlin source code
    • jni: This holds the native code using the Java Native Interface (JNI)
    • gen: This holds the Java files generated by Android Studio
    • res: This holds application resources, for example, drawable files, layout files, strings, and so on
    • assets: This holds files that should be compiled into an .apk file with no modification
    • test: This holds the test source code
    • build.gradle: This is the module level build configuration
    • build.gradle: This is the project level build configuration

Choose File | Project Structure to change settings for the project in the following screenshot:

It contains the following sections:

  • SDK Location: This sets the location of the JDK, Android SDK, and Android NDK that your project uses
  • Project: This sets Gradle and Android Gradle plugin versions
  • Modules: This edits module-specific build configurations

The Modules section is divided in the following tabs:

  • Properties: This sets the versions of the SDK and build tools for module building
  • Signing: This sets the certificate for APK signing
  • Flavors: This defines flavors for the module
  • Build Types: This defines build types for the module
  • Dependencies: This sets dependencies needed by the module

Please refer to the following screenshot:

 

Defining build types and flavors


We are approaching an important phase of our project--defining build variants for our application. Build variant stands for a unique version of an Android application.

They are unique because they override some of the application attributes or resources.

Each build variant is configured per module level.

Let's extend our build.gradle! Put the following code in the android section of the build.gradle file:

    android { 
      ... 
      buildTypes { 
        debug { 
          applicationIdSuffix ".dev" 
        } 
        staging { 
          debuggable true 
          applicationIdSuffix ".sta" 
        } 
        preproduction { 
          applicationIdSuffix ".pre" 
        } 
           release {} 
        } 
       ... 
    }  

We defined the following buildTypes for our application--debug, release, staging, and preproduction.

Product flavors are created in a similar way like buildTypes. You need to add them to productFlavors and configure the needed settings. The following code snippet demonstrates this:

    android { 
      ... 
      defaultConfig {...} 
      buildTypes {...} 
      productFlavors { 
        demo { 
          applicationIdSuffix ".demo" 
          versionNameSuffix "-demo" 
        } 
        complete { 
          applicationIdSuffix ".complete" 
          versionNameSuffix "-complete" 
        } 
        special { 
          applicationIdSuffix ".special" 
          versionNameSuffix "-special" 
        } 
       } 
    } 

After you create and configure your productFlavors, click on Sync Now in the notification bar.

You need to wait a while for the process to be done. Names for Build Variants are formed by the <product-flavor><Build-Type> convention. Here are some examples:

    demoDebug 
    demoRelease 
    completeDebug 
    completeRelease 

You can change the build variant to the one that you want to build and run. Go to Build, select Build Variant, and select completeDebug from the drop-down menu.

The Main/source set is shared between all build variants in your application. If you need to create a new source set, you can do that for certain build types, product flavors, and their combinations.

All source set files and directories must be organized in a specific way, similar to the Main/Source set. Kotlin class files that are specific to your debug build type must be located in src/debug/kotlin/directory.

In order to learn how to organize your files, open the terminal window (View | ToolWindows | Terminal) and execute the following command line:

./gradlew sourceSets

Take a look at the output carefully. The report is understandable and self-explanatory. Android Studio doesn't create the sourceSets directories. It's a work that has to be done by you.

If desired, you can change the location where Gradle is looking for a source set using the sourceSets block. Let's update our build configuration. We will update the following expected source code paths:

    android { 
      ... 
      sourceSets { 
       main { 
       java.srcDirs = [ 
                'src/main/kotlin', 
                'src/common/kotlin', 
                'src/debug/kotlin', 
                'src/release/kotlin', 
                'src/staging/kotlin', 
                'src/preproduction/kotlin', 
                'src/debug/java', 
                'src/release/java', 
                'src/staging/java', 
                'src/preproduction/java', 
                'src/androidTest/java', 
                'src/androidTest/kotlin' 
        ] 
        ... 
     } 

Code and resources that you want packaged only with certain configurations, you can store in the sourceSets directories. Here are given examples for build with the demoDebug build variant; this build variant is a product of a demo product flavor and debug build type. In Gradle, the following priority is given to them:

    src/demoDebug/ (build variant source set) 
    src/debug/ (build type source set) 
    src/demo/ (product flavor source set) 
    src/main/ (main source set) 

This is the priority order that Gradle uses during the build process and considers it when applying the following build rules:

  • It compiles source code in the java/ and kotlin/ directories together
  • It merges manifests together into a single manifest
  • It merges files in the values/ directories
  • It merges resources in the res/ and asset/ directories

The lowest priority is given to resources and manifests included with library module dependencies.

 

Additional libraries


We configured our build types and flavors, now we will need some third-party libraries. We will use and add support for Retrofit, OkHttp, and Gson. This is an explanation for each of them:

  • Retrofit is a type-safe HTTP client for Android and Java by Square, Inc. Retrofit is one of the most popular HTTP client library for Android as a result of its simplicity and its great performance compared to the others.
  • OkHttp is an HTTP client that's efficient by default--HTTP/2 support allows all requests to the same host to share a socket.
  • Gson is a Java library that can be used to convert Java objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including preexisting objects that you do not have a source code for.

There are a few open source projects that can convert Java objects to JSON. Later in this book, we will add Kotson to provide Gson bindings for Kotlin.

Let's extend build.gradle with dependencies for Retrofit and Gson:

    dependencies { 
      ... 
      compile 'com.google.code.gson:gson:2.8.0' 
      compile 'com.squareup.retrofit2:retrofit:2.2.0' 
      compile 'com.squareup.retrofit2:converter-gson:2.0.2' 
      compile 'com.squareup.okhttp3:okhttp:3.6.0' 
      compile 'com.squareup.okhttp3:logging-interceptor:3.6.0' 
      ... 
    } 

After you updated your Gradle configuration, sync it again when asked!

 

Getting familiar with Android Manifest


Every application must have an AndroidManifest.xml file and the file must have exactly that name. Its location is in its root directory, and, in each module, it contains essential information about your application to the Android system. The manifest file is responsible for defining the following:

  • Naming a package for the application
  • Describing the components of the application--activities (screens), services, broadcast receivers (messages), and content providers (database access)
  • Permissions that application must have in order to access protected parts of the Android API
  • Permissions that other applications must have in order to interact with the application's components, such as content providers

The following code snippet shows the general structure of the manifest file and elements that it can contain:

    <?xml version="1.0" encoding="utf-8"?> 
    <manifest> 
      <uses-permission /> 
      <permission /> 
      <permission-tree /> 
      <permission-group /> 
      <instrumentation /> 
      <uses-sdk /> 
      <uses-configuration />   
      <uses-feature />   
      <supports-screens />   
      <compatible-screens />   
      <supports-gl-texture />   
 
      <application> 
        <activity> 
          <intent-filter> 
            <action /> 
              <category /> 
                <data /> 
            </intent-filter> 
            <meta-data /> 
        </activity> 
 
        <activity-alias> 
          <intent-filter> . . . </intent-filter> 
          <meta-data /> 
        </activity-alias> 
 
        <service> 
          <intent-filter> . . . </intent-filter> 
          <meta-data/> 
        </service> 
 
        <receiver> 
          <intent-filter> . . . </intent-filter> 
          <meta-data /> 
        </receiver> 
        <provider> 
          <grant-uri-permission /> 
          <meta-data /> 
          <path-permission /> 
        </provider> 
 
        <uses-library /> 
      </application> 
    </manifest> 
 

Main Application class


Each Android application defines its main Application class. The Application class in Android is the base class within an Android application that contains all other components, such as activities and services. The Application class, or any subclass of the Application class, is instantiated before any other class when the process for your application/package is created.

We will create an Application class for Journaler. Locate the main sources directory. Expand it, and if there is no Kotlin sources directory, create it. Then, create the package com and subpackage journaler; to do so, right-click on the Kotlin directory and choose New | Package. Once you've created the package structure, right-click on the journaler package and choose New | KotlinFile/Class. Name it Journaler. Journaler.kt is created.

Each Application class must extend the Android Application class as shown in our example:

    package com.journaler 
 
    import android.app.Application 
    import android.content.Context 
 
 
    class Journaler : Application() { 
 
      companion object { 
        var ctx: Context? = null 
      } 
 
      override fun onCreate() { 
        super.onCreate() 
        ctx = applicationContext 
      } 
 
    } 

For now, our main Application class will provide us with static access to application context. What this context is will be explained later. However, Android will not use this class until it's mentioned in manifest. Open the app module android manifest and add the following block of code:

    <manifest xmlns:android="http://schemas.android.com/apk/
    res/android" package="com.journaler"> 
 
    <application 
        android:name=".Journaler" 
        android:allowBackup="false" 
        android:icon="@mipmap/ic_launcher" 
        android:label="@string/app_name" 
        android:roundIcon="@mipmap/ic_launcher_round" 
        android:supportsRtl="true" 
        android:theme="@style/AppTheme"> 
 
    </application> 
    </manifest> 

With android:name=".Journaler", we tell Android which class to use.

 

Your first screen


We created an application with no screens. We will not waste time, we will create one! Create a new package named activity where all our screen classes will be defined, and create your first Activity class named MainActivity.kt. We will start with one simple class:

    package com.journaler.activity 
 
    import android.os.Bundle 
    import android.os.PersistableBundle 
    import android.support.v7.app.AppCompatActivity 
    import com.journaler.R 

    class MainActivity : AppCompatActivity() { 
      override fun onCreate(savedInstanceState: Bundle?,
      persistentState: PersistableBundle?) { 
        super.onCreate(savedInstanceState, persistentState) 
        setContentView(R.layout.activity_main) 
      } 
    } 

Soon, we will explain the meaning of all these lines. For now, it's important to note that setContentView(R.layout.activity_main) assigns UI resource to our screen and activity_main is a name of the XML defining it. Since we don't have it yet, we will create it. Locate res directory under the main directory. If there is no layout folder there, create one and then create a new layout named activity_main by right-clicking on layout directory and choosing the New | Layout resource file. Assign activity_main as its name and LinearLayout as its root element. The content of the file should be similar to this:

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/
     apk/res/android" 
      android:orientation="vertical" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent"> 
 
   </LinearLayout> 

There is one more thing to do before we are ready to run our application: we must tell our manifest about this screen. Open the main manifest file and add the following piece of code:

    <application ... > 
      <activity 
        android:name=".activity.MainActivity" 
        android:configChanges="orientation" 
        android:screenOrientation="portrait"> 
        <intent-filter> 
          <action android:name="android.intent.action.MAIN" /> 
          <category android:name="android.intent.category.LAUNCHER" /> 
        </intent-filter> 
      </activity> 
    </application> 

We will explain all these attributes soon; all you need to know for now is that your application is ready to run. However, before that, commit and push your work. You don't want to lose it!

 

Summary


In this chapter, we introduced the basics of Android and gave glimpses of Kotlin. We configured a working environment and made the first screen of our application.

In the next chapter, we will go deeper into the matter of Android. You will learn how to build your application and customize different variants. We will also cover different ways of running the application.

 

About the Author

  • Miloš Vasić

    Miloš Vasić is a software engineer, author and open source enthusiasts. Miloš holds a Bachelor degree in Programming of computer graphics and Master degree in the field of Android programming, both degrees he obtained at the Singidunum University. He published his first book Fundamental Kotlin in October 2016 and thus achieved his dream of becoming an author.

    Browse publications by this author

Latest Reviews

(13 reviews total)
Already outdated. It is not possible to follow this instructions to get the ending application because some parts are missing. But at the same time it was a lot better than nothing to learn this new topic. So I find it still very valuable.
Acquisto comodo e facile, tutto come previsto senza intoppi e molto rapido e puntuale. Materiale reperibile da subito appena effettuato l'acquisto. Il sito è molto intuitivo e la scelta è stata facile, ottima l'idea delle preview dei capitoli online
Basic instructions with examples in Kotlin

Recommended For You

Android Programming with Kotlin for Beginners

Build smart looking Kotlin apps with UI and functionality for the Android platform

By John Horton
Learn Kotlin Programming - Second Edition

Delve into the world of Kotlin and learn to build powerful Android and web applications

By Stephen Samuel and 1 more
Hands-on Design Patterns with Kotlin

Make the most of Kotlin by leveraging design patterns and best practices to build scalable and high performing apps

By Alexey Soshin
Java Coding Problems

Develop your coding skills by exploring Java concepts and techniques such as Strings, Objects and Types, Data Structures and Algorithms, Concurrency, and Functional programming

By Anghel Leonard