Book Image

How to Build Android Apps with Kotlin

By : Alex Forrester, Eran Boudjnah, Alexandru Dumbravan, Jomar Tigcal
Book Image

How to Build Android Apps with Kotlin

By: Alex Forrester, Eran Boudjnah, Alexandru Dumbravan, Jomar Tigcal

Overview of this book

Are you keen to get started building Android 11 apps, but don’t know where to start? How to Build Android Apps with Kotlin is a comprehensive guide that will help kick-start your Android development practice. This book starts with the fundamentals of app development, enabling you to utilize Android Studio and Kotlin to get started building Android projects. You'll learn how to create apps and run them on virtual devices through guided exercises. Progressing through the chapters, you'll delve into Android’s RecyclerView to make the most of lists, images, and maps, and see how to fetch data from a web service. Moving ahead, you'll get to grips with testing, learn how to keep your architecture clean, understand how to persist data, and gain basic knowledge of the dependency injection pattern. Finally, you'll see how to publish your apps on the Google Play store. You'll work on realistic projects that are split up into bitesize exercises and activities, allowing you to challenge yourself in an enjoyable and attainable way. You'll build apps to create quizzes, read news articles, check weather reports, store recipes, retrieve movie information, and remind you where you parked your car. By the end of this book, you'll have the skills and confidence to build your own creative Android applications using Kotlin.
Table of Contents (17 chapters)
Preface
12
12. Dependency Injection with Dagger and Koin

Intents, Tasks, and Launch Modes

Up until now, you have been using the standard behavior for creating Activities and moving from one Activity to the next. The flow you have been using is the default, and in most cases, this will be the one you choose to use. When you open the app from the launcher with the default behavior, it creates its own Task, and each Activity you create is added to a back stack, so when you open three Activities one after the other as part of your user's journey, pressing the back button three times will move the user back through the previous screens/Activities and then go back to the device's home screen, while still keeping the app open.

The launch mode for this type of Activity is called Standard; it is the default and doesn't need specifying in the Activity element of AndroidManifest.xml. Even if you launch the same Activity three times, one after the other, there will be three instances of the same activity that exhibit the behavior described previously.

For some apps, you may want to change this behavior. The scenario most commonly used that doesn't conform to this pattern is when you want to relaunch an Activity without creating a new separate instance. A common use case for this is when you have a home screen with a main menu and different news stories that the user can read. Once the user has gone through to an individual news story and then presses another news story title from the menu, when the user presses the back button, they will expect to return to the home screen and not the previous news story. The launch mode that can help here is called singleTop. If a singleTop Activity is at the top of the Task (top, in this context, means most recently added), when the same singleTop Activity is launched, then instead of creating a new Activity, it uses the same Activity and runs the onNewIntent callback. In the preceding scenario, this could then use the same activity to display a different news story. In this callback, you receive an intent, and you can then process this intent as you have done previously in onCreate.

There are two other launch modes to be aware of, called SingleTask and SingleInstance. These are not for general use and are only used for special scenarios. For both of these launch modes, only one Activity of this type can exist in the application and it is always at the root of its Task. If you launch an Activity with this launch mode, it will create a new Task. If it already exists, then it will route the intent through the onNewIntent call and not create another instance. The only difference between SingleTask and SingleInstance is that SingleInstance is the one and only Activity of its Task. No new Activities can be launched into its Task. In contrast, SingleTask does allow other Activities to be launched into its Task, but the SingleTask Activity is always at the root.

These launch modes can be added to the XML of AndroidManifest.xml or created programmatically by adding intent flags. The most common ones used are the following:

  • FLAG_ACTIVITY_NEW_TASK: Launches the Activity into a new Task.
  • FLAG_ACTIVITY_CLEAR_TASK: Clears the current Task, so finishes all Activities and launches the Activity at the root of the current Task.
  • FLAG_ACTIVITY_SINGLE_TOP: Replicates the launch mode of the launchMode="singleTop" XML.
  • FLAG_ACTIVITY_CLEAR_TOP: Removes all Activities that are above any other instances of the same activity. If this is launched on a standard launch mode Activity, then it will clear the Task down to the first existing instance of the same Activity, and then launch another instance of the same Activity. This will probably not be what you want, and you can launch this flag with the FLAG_ACTIVITY_SINGLE_TOP flag to clear all the activities down to the same instance of the Activity you are launching and not create a new instance, but instead route a new intent to the existing Activity. To create an Activity using these two intent flags, you would do the following:
    val intent = Intent(this, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or
        Intent.FLAG_ACTIVITY_SINGLE_TOP
    }
    startActivity(intent)

If an intent launches an Activity with one or more of the intent flags specified in the preceding code block, then the launch mode specified overrides the one that is set in the AndroidManifest.xml file.

Intent flags can be combined in multiple ways. For more information, see the official documentation at https://developer.android.com/reference/android/content/Intent.

You'll explore the differences in the behavior of these two launch modes in the next exercise.

Exercise 2.06: Setting the Launch Mode of an Activity

This exercise has many different layout files and Activities to illustrate the two most commonly used launch modes. Please download the code from http://packt.live/2LFWo8t and then we will go through the exercise at http://packt.live/2XUo3Vk:

  1. Open up the activity_main.xml file and examine it.

    This illustrates a new concept when using layout files. If you have a layout file and you would like to include it in another layout, you can use the <include> XML element (have a look at the following snippet of the layout file):

    <include layout="@layout/letters"
        android:id="@+id/letters_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/      launch_mode_standard"/>
    <include layout="@layout/numbers"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/      launch_mode_single_top"/> 

    The preceding layout uses the include XML element to include the two layout files: letters.xml and numbers.xml.

  2. Open up and inspect the letters.xml and numbers.xml files found in the res | layout folder. These are very similar and are only differentiated from the buttons they contain by the ID of the buttons themselves and the text label they display.
  3. Run the app and you will see the following screen:
    Figure 2.20: App displaying both the standard and single top modes

    Figure 2.20: App displaying both the standard and single top modes

    In order to demonstrate/illustrate the difference between standard and singleTop activity launch modes, you have to launch two or three activities one after the other.

  4. Open up MainActivity and examine the contents of the code block in onCreate(savedInstanceState: Bundle?) after the signature:
        val buttonClickListener = View.OnClickListener { view ->
            when (view.id) {
                R.id.letterA -> startActivity(Intent(this,               ActivityA::class.java))
                //Other letters and numbers follow the same pattern/flow
                else -> {
                    Toast.makeText(
                        this,
                        getString(R.string.unexpected_button_pressed),
                        Toast.LENGTH_LONG
                    )
                    .show()
                }
            }
        }
        findViewById<View>(R.id.letterA).setOnClickListener(buttonClickListener)
        //The buttonClickListener is set on all the number and letter views
    }

    The logic contained in the main Activity and the other activities is basically the same. It displays an Activity and allows the user to press a button to launch another Activity using the same logic of creating a ClickListener and setting it on the button you saw in Exercise 2.05, Retrieving a Result from an Activity.

  5. Open the AndroidManifest.xml file and you will see the following:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.launchmodes">
        <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/Theme.LaunchModes">
            <activity android:name=".ActivityA"           android:launchMode="standard"/>
            <activity android:name=".ActivityB"           android:launchMode="standard"/>
            <activity android:name=".ActivityC"           android:launchMode="standard"/>
            <activity android:name=".ActivityOne"           android:launchMode="singleTop"/>
            <activity android:name=".ActivityTwo"           android:launchMode="singleTop"/>
            <activity android:name=".ActivityThree"           android:launchMode="singleTop"/>
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name=                  "android.intent.action.MAIN" />
                    <category android:name=                  "android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>

    You launch an Activity based on a button pressed on the main screen, but the letter and number activities have a different launch mode, which you can see specified in the AndroidManifest.xml file.

    The standard launch mode is specified here to illustrate the difference between standard and singleTop, but standard is the default and would be how the Activity is launched if the android:launchMode XML attribute was not present.

  6. Press one of the letters under the Standard heading and you will see the following screen (with A or letters C or B):
    Figure 2.21: The app displaying standard activity

    Figure 2.21: The app displaying standard activity

  7. Keep on pressing any of the letter buttons, which will launch another Activity. Logs have been added to show this sequence of launching activities. Here is the log after pressing 10 letter Activities randomly:
    2019-10-23 20:50:51.097 15281-15281/com.example.launchmodes D/MainActivity: onCreate
    2019-10-23 20:51:16.182 15281-15281/com.example.launchmodes D/Activity B: onCreate
    2019-10-23 20:51:18.821 15281-15281/com.example.launchmodes D/Activity B: onCreate
    2019-10-23 20:51:19.353 15281-15281/com.example.launchmodes D/Activity C: onCreate
    2019-10-23 20:51:20.334 15281-15281/com.example.launchmodes D/Activity A: onCreate
    2019-10-23 20:51:20.980 15281-15281/com.example.launchmodes D/Activity B: onCreate
    2019-10-23 20:51:21.853 15281-15281/com.example.launchmodes D/Activity B: onCreate
    2019-10-23 20:51:23.007 15281-15281/com.example.launchmodes D/Activity C: onCreate
    2019-10-23 20:51:23.887 15281-15281/com.example.launchmodes D/Activity B: onCreate
    2019-10-23 20:51:24.349 15281-15281/com.example.launchmodes D/Activity C: onCreate

    If you observe the preceding log, every time the user presses a character button in launch mode, a new instance of the character Activity is launched and added to the back stack.

  8. Close the app, making sure it is not backgrounded (or in the recents/overview menu) but is actually closed, and then open the app again and press one of the number buttons under the Single Top heading:
    Figure 2.22: The app displaying the Single Top activity

    Figure 2.22: The app displaying the Single Top activity

  9. Press the number buttons 10 times, but make sure you press the same number button at least twice sequentially before pressing another number button.

    The logs you should see in the Logcat window (View | Tool Windows | Logcat) should be similar to the following:

    2019-10-23 21:04:50.201 15549-15549/com.example.launchmodes D/MainActivity: onCreate
    2019-10-23 21:05:04.503 15549-15549/com.example.launchmodes D/Activity 2: onCreate
    2019-10-23 21:05:08.262 15549-15549/com.example.launchmodes D/Activity 3: onCreate
    2019-10-23 21:05:09.133 15549-15549/com.example.launchmodes D/Activity 3: onNewIntent
    2019-10-23 21:05:10.684 15549-15549/com.example.launchmodes D/Activity 1: onCreate
    2019-10-23 21:05:12.069 15549-15549/com.example.launchmodes D/Activity 2: onNewIntent
    2019-10-23 21:05:13.604 15549-15549/com.example.launchmodes D/Activity 3: onCreate
    2019-10-23 21:05:14.671 15549-15549/com.example.launchmodes D/Activity 1: onCreate
    2019-10-23 21:05:27.542 15549-15549/com.example.launchmodes D/Activity 3: onNewIntent
    2019-10-23 21:05:31.593 15549-15549/com.example.launchmodes D/Activity 3: onNewIntent
    2019-10-23 21:05:38.124 15549-15549/com.example.launchmodes D/Activity 1: onCreate

You'll notice that instead of calling onCreate when you pressed the same button again, the Activity is not created, but a call is made to onNewIntent. If you press the back button, you'll notice that it will take you less than 10 clicks to back out of the app and return to the home screen, reflecting the fact that 10 activities have not been created.

Activity 2.01: Creating a Login Form

The aim of this activity is to create a login form with username and password fields. Once the values in these fields are submitted, check these entered values against hardcoded values and display a welcome message if they match, or an error message if they don't, and return the user to the login form. The steps needed to achieve this are the following:

  1. Create a form with username and password EditText Views and a LOGIN button.
  2. Add a ClickListener interface to the button to react to a button press event.
  3. Validate that the form fields are filled in.
  4. Check the submitted username and password fields against the hardcoded values.
  5. Display a welcome message with the username if successful and hide the form.
  6. Display an error message if not successful and redirect the user back to the form.

There are a few possible ways that you could go about trying to complete this activity. Here are three ideas for approaches you could adopt:

  • Use a singleTop Activity and send an intent to route to the same Activity to validate the credentials.
  • Use a standard Activity to pass a username and password to another Activity and validate the credentials.
  • Use startActivityForResult to carry out the validation in another Activity and then return the result.

The completed app, upon its first loading, should look as in Figure 2.23:

Figure 2.23: The app display when first loaded

Figure 2.23: The app display when first loaded

Note

The solution to this activity can be found at: http://packt.live/3sKj1cp.

The source code for all the exercises and the activity in this chapter is located at http://packt.live/3o12sp4.