initial commit

master
PhilipOsztromok 3 months ago
commit 5cf26f0abf
  1. 22
      android/android.html
  2. 36
      android/androiddevelopmentet/androiddevelopmentet.html
  3. 876
      android/androiddevelopmentet/architecture.html
  4. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster01.png
  5. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster02.png
  6. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster03.png
  7. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster04.png
  8. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster05.png
  9. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster06.png
  10. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster07.png
  11. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster08.png
  12. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster09.png
  13. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster10.png
  14. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster11.png
  15. BIN
      android/androiddevelopmentet/assets/monster_images/png/monster12.png
  16. 4945
      android/androiddevelopmentet/assets/monster_images/svg/monster01.svg
  17. 5197
      android/androiddevelopmentet/assets/monster_images/svg/monster02.svg
  18. 5983
      android/androiddevelopmentet/assets/monster_images/svg/monster03.svg
  19. 66
      android/androiddevelopmentet/assets/monster_images/svg/monster04.svg
  20. 5014
      android/androiddevelopmentet/assets/monster_images/svg/monster05.svg
  21. 6137
      android/androiddevelopmentet/assets/monster_images/svg/monster06.svg
  22. 4734
      android/androiddevelopmentet/assets/monster_images/svg/monster07.svg
  23. 4445
      android/androiddevelopmentet/assets/monster_images/svg/monster08.svg
  24. 3982
      android/androiddevelopmentet/assets/monster_images/svg/monster09.svg
  25. 3159
      android/androiddevelopmentet/assets/monster_images/svg/monster10.svg
  26. 6307
      android/androiddevelopmentet/assets/monster_images/svg/monster11.svg
  27. 3095
      android/androiddevelopmentet/assets/monster_images/svg/monster12.svg
  28. 0
      android/androiddevelopmentet/assets/monster_text.txt
  29. 323
      android/androiddevelopmentet/exploring.html
  30. 49
      android/androiddevelopmentet/fundamentals.html
  31. 61
      android/androiddevelopmentet/gettingstarted.html
  32. BIN
      android/androiddevelopmentet/images/figure1.png
  33. BIN
      android/androiddevelopmentet/images/figure10.png
  34. BIN
      android/androiddevelopmentet/images/figure11.png
  35. BIN
      android/androiddevelopmentet/images/figure12.png
  36. BIN
      android/androiddevelopmentet/images/figure13.png
  37. BIN
      android/androiddevelopmentet/images/figure19.png
  38. BIN
      android/androiddevelopmentet/images/figure21.png
  39. BIN
      android/androiddevelopmentet/images/figure22.png
  40. BIN
      android/androiddevelopmentet/images/figure23.png
  41. BIN
      android/androiddevelopmentet/images/figure24.png
  42. BIN
      android/androiddevelopmentet/images/figure29.png
  43. BIN
      android/androiddevelopmentet/images/figure30.png
  44. BIN
      android/androiddevelopmentet/images/figure31.png
  45. BIN
      android/androiddevelopmentet/images/figure45.png
  46. BIN
      android/androiddevelopmentet/images/figure5.png
  47. BIN
      android/androiddevelopmentet/images/figure7.png
  48. BIN
      android/androiddevelopmentet/images/monster01.png
  49. 48
      android/androidstudioet/analyze.html
  50. 36
      android/androidstudioet/androidstudioet.html
  51. 48
      android/androidstudioet/create.html
  52. 48
      android/androidstudioet/explore.html
  53. BIN
      android/androidstudioet/images/Git-Logo-2Color.png
  54. BIN
      android/androidstudioet/images/figure1.png
  55. BIN
      android/androidstudioet/images/figure10.png
  56. BIN
      android/androidstudioet/images/figure11.png
  57. BIN
      android/androidstudioet/images/figure12.png
  58. BIN
      android/androidstudioet/images/figure13.png
  59. BIN
      android/androidstudioet/images/figure14.png
  60. BIN
      android/androidstudioet/images/figure15.png
  61. BIN
      android/androidstudioet/images/figure16.png
  62. BIN
      android/androidstudioet/images/figure17.png
  63. BIN
      android/androidstudioet/images/figure18.png
  64. BIN
      android/androidstudioet/images/figure19.png
  65. BIN
      android/androidstudioet/images/figure2.png
  66. BIN
      android/androidstudioet/images/figure20.png
  67. BIN
      android/androidstudioet/images/figure22.png
  68. BIN
      android/androidstudioet/images/figure23.png
  69. BIN
      android/androidstudioet/images/figure26.png
  70. BIN
      android/androidstudioet/images/figure27.png
  71. BIN
      android/androidstudioet/images/figure3.png
  72. BIN
      android/androidstudioet/images/figure31.png
  73. BIN
      android/androidstudioet/images/figure37.png
  74. BIN
      android/androidstudioet/images/figure38.png
  75. BIN
      android/androidstudioet/images/figure39.png
  76. BIN
      android/androidstudioet/images/figure4.png
  77. BIN
      android/androidstudioet/images/figure40.png
  78. BIN
      android/androidstudioet/images/figure43.png
  79. BIN
      android/androidstudioet/images/figure44.png
  80. BIN
      android/androidstudioet/images/figure45.png
  81. BIN
      android/androidstudioet/images/figure5.png
  82. BIN
      android/androidstudioet/images/figure6.png
  83. BIN
      android/androidstudioet/images/figure7.png
  84. BIN
      android/androidstudioet/images/figure8.png
  85. BIN
      android/androidstudioet/images/figure9.png
  86. 48
      android/androidstudioet/manage.html
  87. 87
      android/kotlinessentialtraining/appendixa.html
  88. 68
      android/kotlinessentialtraining/appendixb.html
  89. 575
      android/kotlinessentialtraining/classes.html
  90. 104
      android/kotlinessentialtraining/code.html
  91. 76
      android/kotlinessentialtraining/code/0105.html
  92. 82
      android/kotlinessentialtraining/code/0301.html
  93. 85
      android/kotlinessentialtraining/code/0303.html
  94. 81
      android/kotlinessentialtraining/code/0304.html
  95. 91
      android/kotlinessentialtraining/code/0305.html
  96. 100
      android/kotlinessentialtraining/code/0306.html
  97. 98
      android/kotlinessentialtraining/code/0307.html
  98. 78
      android/kotlinessentialtraining/code/0308.html
  99. 80
      android/kotlinessentialtraining/code/0309.html
  100. 113
      android/kotlinessentialtraining/code/0401.html
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>New Website</title>
<link href="styles/styles.css" rel="stylesheet" type="text/css">
<link href="../styles/homepagestyles.css" rel="stylesheet">
<link href="styles/styles.css" rel="stylesheet" type="text/css">
</head>
<body id="homebody">
<div class="main_grid">
<div class="header">My Learning Website - Android Development</div>
</div>
<div class="main-content">
<div class="homepagebutton"><a href="androidstudioet/androiddevelopmentet.html">Android Studio Essential Training</a></div>
<div class="homepagebutton"><a href="androiddevelopmentet/androiddevelopmentet.html">Android Development Essential Training</a></div>
<div class="homepagebutton"><a href="kotlinessentialtraining/kotlinessentialtraining.html">Kotlin Essential Training</a></div>
<div class="homepagebutton"><a href="/index.html">Home</a></div>
</div>
</body>
</html>

@ -0,0 +1,36 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Studio Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2019</h2>
</div>
<article class="contents-article">
<section class="main_grid">
<div><a class="tile" href="fundamentals.html">Chapter 1 - Android Development Fundamentals</a></div>
<div><a class="tile" href="gettingstarted.html">Chapter 2 - Getting Started</a></div>
<div><a class="tile" href="exploring.html">Chapter 3 - Exploring Android Projects</a></div>
<div><a class="tile" href="architecture.html">Chapter 4 - Android App Architecture</a></div>
<div><a class="tile" href="/android/android.html">Android Page</a></div>
<div><a class="tile" href="/index.html">Home</a></div>
</section>
</article>
</body>
</html>

@ -0,0 +1,876 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2019</h2>
<h2 class="episodetitle">Android App Architecture</h2>
</div>
<article>
<h2 class="sectiontitle">Define Screens with Activities</h2>
<p>An activity in Android equates roughly to something an app can do and if the app is designed for a phone or a tables, activities manage screens.</p>
<p>An activity screen can server as an interface for smaller user interface components called fragments so it may not always look the same, but it is always managed by an activity.</p>
<p>When an app is started via the launcher icon, the app framework looks for the apps launcher activity which is identified by the intent filter in the apps manifest. For exercise 04_02 the intent filter is shown below.</p>
<pre class="inset">
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;
&lt;/intent-filter&gt;</pre>
<p>Note that the intent filer has an action and a category. When the app starts, it will run the class defined by the action category and this class is of course, part of the class hierarchy.</p>
<p>For example, we can look at this class in our app and we will see that it extends a class called AppCompatActivity(). If we press control and click on this class name, we can see that it extends FragmentActivity and also implements three interfaces. We can continue in this way and see that FragmentActivity extends ComponentActivity which extends Activity and which extends ContextThemeWrapper and so on.</p>
<p>This highlights the fact that each activity is actually a type of context and the other type of context is the application context.</p>
<p>Now, returning to the Main class, when this executes, it calls a series of what are known as lifestyle functions which are callbacks made automatically by the app framework using interfaces that the activity implements and these are marked with the override keyword.</p>
<p>The most common of these is onCreate.</p>
<pre class="inset">
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
fab.setOnClickListener { view -&gt;
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
}</pre>
<p>So, we are calling the super version of the same function first. Typically, you will then call setContentView and pass it a reference to a layout file, R.layout.activity_main. This file is stored in the resources folder and again, we can jump over to it by holding control and clicking the filename.</p>
<p>We can also jump to its location within the navigation panel by clicking on the Scroll from Source icon (which looks like a little wheel and is just next to the scope drop-down menu).</p>
<p>So now, we can summarise the startup process as:</p>
<pre class="inset-overflow">
• From MainActivity, the onCreate function is called.
• From onCreate, the setContentView function is called.
• The setContentView function loads the screen design which is defined in the XML layout file.</pre>
<h2 class="sectiontitle">Implement Designs in XML Layouts</h2>
<p>The setContentView takes an integer value as an argument and this is the resource ID of the XML layout file. Here is the onCreate function from where the call to setContentView is made.</p>
<pre class="inset">
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
fab.setOnClickListener { view -&gt;
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
}</pre>
<p>This value is stored in a class called R which is auto-generated.</p>
<p>You will never make changes to the R class. If you do happen to make changes here, there is a background process which regenerates the class so any changes would be wiped out. Layout (R.layout.activity_main)references the layout directory in the resources directory and is followed by the name of the file without the extension.</p>
<p>We can jump to this file by pressing control and clicking on the filename. In the project window, you can go to the file’s location (as noted in the previous section) by clicking inside the code window and then clicking on the Scroll from Source icon.</p>
<p>This application has two layout files, one of which is activity_main.xml.</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"&gt;
&lt;com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay"&gt;
&lt;androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/&gt;
&lt;/com.google.android.material.appbar.AppBarLayout&gt;
&lt;include layout="@layout/content_main"/&gt;
&lt;com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email"/&gt;
&lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&gt; </pre>
<p>The other layout file is called contant_main.xml and this is nested or included within activity_main.xml layout file. So activity_main.xml is referred to as the outer file and content_main.xml is the inner layout file.</p>
<p>The floating action button (that’s the button displayed in the bottom right corner in the app and this is shown in this image) is defined in the outer layout.</p>
<img src="images/figure19.png" alt="a screenshot of the running app">
<p>There are two implications here. The first is that if we make any changes to the layout in the inner file, this will not affect the floating action button. The second is that when the app is running, if we were to scroll in the inner layout, this again will have no effect on the floating action button (for instance, it won’t move around as the inner file scrolls up and down).</p>
<p>Typically, when you want to make any changes, you will do this within the nested file.</p>
<p>In this case, the nested file contains just one component and this is a text view component which is wrapped in a constraint layout container.</p>
<p>Constraint layout is one kind of view group and is designed to manage the layout of multiple views.</p>
<p>The text view is a child component, it is a child of the constraint layout. Its position is dictated by four attributes in the layout file and the TextView element, with these constraints, is</p>
<pre class="inset">
&lt;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"/&gt;</pre>
<p>Note that these positional constraints all start with layout_constraint. Note that all four reference the edge of the screen (the top, the bottom, the left and the right) and all of them also reference parent with the result being that this component is position in the centre of the screen.</p>
<p>If we want to change this, we can go to the layout’s design view and select the TextView component and we should see something like the view shown.</p>
<img src="images/figure21.png" alt="the content_main.xml layout file shown in design view">
<p>Now, in the right-hand pane we can see the layout. To make this a little clearer, here is an expanded view of this.</p>
<img src="images/figure22.png" alt="enlarged view of the layout section on the right-hand side of the previous image">
<p>First of all, we will click on the grey circle at the bottom and this removes the bottom constraint with the result that the component floats all the way to the top.</p>
<p>If we want to position it a bit further down, there are two ways to do this (actually, three if you count direct manipulation of the code).</p>
<p>We can use the design view to drag and drop it to the desired location and this generates the code for the new position. Alternatively, we can go to the attributes section on the right-hand side and either search for the appropriate attribute manually or (more likely) type the attribute we want into the attributes search box.</p>
<p>In this case, the attribute we want to search for is margin and this will show us the layout margins. If we expand these, we can see the margins for top, left and so on. We can enter a margin of, say, 30 for the top margin and we will then see that it is positioned slightly below the top margin.</p>
<p>Note that there is an option to specify a figure for the margin and this acts as the margin for left, right, top and bottom.</p>
<p>This means that it is possible to provide conflicting information. For instance, if we leave the top margin set to 30 and then insert a figure of 150 for margin, we can see that the TextView is now much further from the top. This is because the value we inserted for margin takes precedence over an edge-specific margin, in this case the top-edge margin.</p>
<p>This is noted in the hint that appears if you hover over margin and this is reproduced below.</p>
<img src="images/figure23.png" alt="the hint for margin which explains the precedence over edge-specific margins">
<p>Now, we can remove the figure of 150 from margin so that we have just the top margin set to 30 but we did not enter a unit. Actually, we can change the value and we will see this reflected in the changed positioning of the TextView but Android Studio shows an error condition of “unknown units” which you can see has resulted in the input box for the top margin displaying a red border.</p>
<p>To fix this, we can either add the units to the value in the input box or to the code in text view (that is, the text view for the layout file rather than the TextView component). We could use px (pixels) as a unit and this works but a warning is displayed that states we should prefer the use of dp which stands for device independent pixels.</p>
<p>Going back to the design view, we will search for size in the attribute search box and one of the attributes we find is textSize which we will change to 36 but notice here that the units are given as sp. In fact, we can specify this as dp, but just as we saw with dp being preferred over px for the margin, we will also see that Android Studio will warn us that sp is preferred over dp for textSize.</p>
<p>Note that sp stands for scale independent pixels and the difference is this. In settings, the user can choose to change the size of text displayed. For instance, there may be an option in Settings &gt; Accessibility for the user to select large text. If the text size has been specified with sp, this will result in the user seeing larger text as expected, but if it has been specified with dp, the text size will not change when the user selects large text.</p>
<p>For more information on this and other measurement units, please see the YouTube video</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5NZKfNH-u_A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 class="sectiontitle">Use the View and ViewGroup Components</h2>
<p>Screens in Android are built using widgets known as Views. Here, we can see our app in Design View in Android Studio and on the left-hand side, there is palette showing these different widgets (or Views).</p>
<img src="images/figure24.png" alt="the app in Design View showing the palette on the left">
<p>We can drag and drop these objects onto our screen and it does seem that it is now in a fixed position (I will add a button in this way), but if we run the app we will see that it has moved to the top of the screen. If you want it to stay in the position where it was dropped, it will have to be anchored.</p>
<p>When you create a new app in Android Studio, the root element (in the most recent versions of Android Studio) is a constraint layout. Actually, we can see ConstraintLayout in the palette by selecting Layouts and this is a[articular kind of view known as a ViewGroup. If we hold down control and click on ConstraintLayout to call up the class, we can see that it actually extends a class called ViewGroup.</p>
<p>A ViewGroup is designed to manage the position of its child views and at the moment, our constraint layout has two child views, a TextView and a Button, so we will look at the first way to anchor a component.</p>
<p>Before I do that, let’s take a brief look at the code in content_main.xml and we will see here that adding the button has generated some code here.</p>
<pre class="inset">
&lt;Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" tools:layout_editor_absoluteY="554dp"
tools:layout_editor_absoluteX="108dp" android:id="@+id/button"/&gt;</pre>
<p>One thing to note which may not be clear from figure 25 is that the button element has been added as a nested element within constraintlayout in the XML code.</p>
<p>Now, I will go back to design view and note that the button is surrounded by constraints just as our TextView widget was when we clicked the bottom constraint to delete it, however, these are white to indicate that they are empty, there are currently no constraints.</p>
<p>I will click on the bottom circle to create a constraint and drag the button down to the bottom of the screen. Going back to text view, I can see that the following line has been added to the code:</p>
<pre class="inset">
app:layout_constraintBottom_toBottomOf="parent"/&gt;</pre>
<p>If I go back to design view and add similar constraints for left and right, the code for button is changed again and we end up with the button element shown below.</p>
<pre class="inset">
&lt;Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"/&gt;</pre>
<p>Note that the code in figure 26 has been tidied up a little bit with respect to positioning without changing the actual code.</p>
<p>So, we have anchored the button to the bottom, left and right and these are all shown in the constraints in figure 26. Our first constraint was a bottom to bottom of constraint and we have also added start to start of and end to end of constraints. These latter two anchor the button to the left and right edges of the screen respectively. We could have used left to left of and right to right of constraints instead, but specifying start rather than left and end rather than right is actually preferred because it means that the app would react more elegantly if the app is run in a language that goes right to left. This doesn’t make a difference here since the button has been centred but let’s say we anchored it to the left only (with a left to left of constraint). The button would then appear on the left-hand side for any user.</p>
<p>In contrast, if we use a start to start of constraint without but not end to end of, this would anchor the button to the left hand side for most users, but it would be anchored to the right hand side if the users language went from right to left (since his or her text would start on the right hand side.</p>
<p>Now, let’s go back to the design view and add a top constrain, but we will anchor the button to the bottom of the text view. We can now see that the button is anchored halfway between the bottom of the text view (note that you will see the figure 8 at the bottom of the layout and this is the bottom margin).</p>
<p>There are other ViewGroups available for your layout and these include the LinearLayout (which allows you to layout objects from top to bottom or from left to right), the FrameLayout (designed to contain a single child view and one that you will not see in Android Studio unless you are looking at an old application, the RelativeLayout which is mostly deprecated and superseded by the ConstraintLayout.</p>
<p>There are also some views under the Widgets heading in the palette and these, in general, are fairly self-explanatory and include items such as the WebView, ImageView, VideoView and so on.</p>
<h2 class="sectiontitle">Display an Image in an Activity</h2>
<p>Android supports a variety of image formats including web formats such as png or jpg files but there are formats that are better, either because they produce smaller file-sizes or they are vector-based and therefore adjust more elegantly to different screen sizes and pixel densities.</p>
<p>For the purpose of demonstrating the use of images, we will start with the app in the state that it was in when we finished the previous section. In the content_main.xml file, which you will recall is the inner file, we will make some changes to the text view object, primarily by giving it a unique id and by changing the text to “My favourite monster”.</p>
<p>With regard to the unique id, it is worth noting that anything you want to refer to programmatically must have a unique id and in Android Studio, a unique id always begins with “@+id/” and is followed by the unique identifier which should be lower vase with underscores if you need to separate words. In this case, we will give the TextView object a unique id of “@+id/headline” and also change the top margin so that the TextView object now looks like this.</p>
<pre class="inset">
&lt;TextView
android:id="@+id/headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My favourite monster"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="30dp"
android:textSize="36sp"/&gt;</pre>
<p>Images are displayed using a component called ImageView and we can drag this onto the layout. When it is first added, you also have the option of selecting an avatar which just helps to see what your image might look like when it has been added.</p>
<p>We can add some constraints to anchor our image to the bottom of the TextView object, the left and right edges of the screen and the bottom edge. You will see that the image is displayed as a small square in the centre of the screen, almost like an icon. It did not, as you may have expected, stretch to fill the available area and, in fact, we need to change some settings before it will do that.</p>
<pre class="inset">
&lt;ImageView
android:layout_width="0dp"
android:layout_height="0dp"
tools:srcCompat="@tools:sample/avatars"
android:id="@+id/imageView"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/headline"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"/&gt;</pre>
<p>The changes we need to make are in the ImageView element in the XML file and this element, before the changes are made, is shown in figure 28. Note that both the layout width and layout height are set to “wrap content” and in both cases, we will set this to 0dp. Back in design view, we can now see that the image has indeed been stretched to fit the area.</p>
<p>However, if we now run the application, we will see the text, but not the image and this is because the image we have used is temporary and is not included with the built app. The image used in the video comes from the assets folder in the git repository which can be found on <a href="https://github.com/davidgassner/AndroidDev2019FirstApp/tree/master/assets">David's GitHub page</a>. I have copied this file into the images folder for this report and I will copy it from there into the app.</p>
<p>The process for copying the file is quite straightforward, I have right-clicked the file in Windows Explorer and selected Copy. Back in Android Studio, I have checked to make sure that I am in Android scope rather than Project scope and then right clicked on the Drawable folder and selected paste and I can see that it is now showing in the folder.</p>
<p>To use this image in my app, it needs to have a resource ID which is the name of the file without the extension. However, since I copied the file directly into the apps folder structure, it is possible that it has not been noticed, so before I do anything with it, I will rebuild the app.</p>
<p>Back in the content_main.xml file, I have removed the line:</p>
<pre class="inset">
tools:srcCompat="@tools:sample/avatars"</pre>
<p>which is the reference to the temporary file. I will replace this line of code with:</p>
<pre class="inset">
android:src="@drawable/monster01"</pre>
<p>Note that when you type src, you can then select from the variable resources and monster1.png is listed there so I don’t need to type out the resource name. Apart from the fact that this involves a bit less typing, this has the added advantage that because I can see the image listed here, I know that it has been recognised as a resource by Android Studio.</p>
<p>Now, if I run the application, I can see the image being displayed. This is how we work with simple image formats such as PNG and JPG but if we want to use more advanced formats, some conversion may be required.</p>
<h2 class="sectiontitle">Convert PNG and SVG Image Files</h2>
<p>WebP is a more contemporary format (it is also a bitmap format but it is compressed smaller than PNG files) and Android versions from 4.3 onwards (that is, API level 18 and above) support transparency. To convert our PNG file to WebP, we just need to right-click on the image in Android Studio (in the resources folder) and select Convert to WebP. As it happens, this image has transparency so we want to ensure that the option to Skip images with transparency is not selected.</p>
<p>Clicking OK shows a preview of what the changed file would look like and it is much smaller than the original. The quality can be adjusted as required and it also shows you how big the WebP file is compared to the original (at a quality level of 100% it is 52% of the size of the original).</p>
<p>Note that when the conversion is complete, we only have one image file (monster01.webp) in our resources folder, monster01.png is no longer there so there is no need to change our code. Recall that the resource name of the image is the filename without the extension.</p>
<p>Another format you can use is an XML format known as VectorDrawable. This is similar to the SVG files you may see on a webpage but SVG is not supported by Android Studio.</p>
<p>Now, to convert an SVG file to the VectorDrawable format, we need to use a tool in Android Studio called the Android Asset Studio.</p>
<p>Going back to the Project scope, we can see that we have an assets folder with a subfolder called monster_images and this contains folders called png and svg which themselves contain the images in png and svg format respectively. This is also shown below.</p>
<img src="images/figure29.png" alt="Android Studio with Project scope selected showing the monster images (on the left) in the assets folder">
<p>We can double click on one of these images and Android Studio will open a preview of it, but we cannot use this image directly in the app.</p>
<p>In Android Studio, we will go back to Android Studio, right-click on app and select New and then Vector Asset. This brings up the dialog box:</p>
<img src="images/figure30.png" alt="the new Vector Asset wizard">
<p>From here, we will select Local file and then navigate to the assets folder within our project and select monster01.svg. There are a couple of other options. The size seems to have defaulted to a square format (24dp x 24dp) and this would distort the image so we want to select Override and then next and finish.</p>
<p>We now have an additional file in the drawable folder and the new file is prefixed with ic_ so it has the filename ic_monster01.xml. Again, we will select the Build menu and Make Project to make sure the asset is recognised in Android Studio.</p>
<p>To modify our app so that it displays the VectorDrawable image, we need to edit the content_main.xml file again and as before, we can see that the file is recognised as an asset by Android Studio so we can select it from the list of suggestions.</p>
<p>We can then run the app again and it looks exactly the same as it did before.</p>
<p>VectorDrawable files are not smaller than WebP files and are actually larger in many cases. However, they are more flexible in that they automatically adjust to the size and density of your screen without distorting the images as a bitmap format might.</p>
<p>To sum up, the two formats, WebP and VectorDrawable give you a lot of flexibility with your images and allow you to select between the smallest possible file or the one that resizes most elegantly.</p>
<h2 class="sectiontitle">Start New Activities with Intents</h2>
<p>In an Android app, you navigate from one screen to another by creating something called an Intent. An intent can include an action which is typically expressed as a constant, but it can also include arbitrary data values known as extras.</p>
<p>In order to navigate, you create an intent that references the current activity as a context and the desired target activity’s class. This creates an instance of the target activity’s class and then loads it. It is the responsibility of the application framework to interpret the Intent.</p>
<p>We will create a new activity in our app to demonstrate this and we do that from the Android scope by right-clicking on app and selecting New and then Activity and Basic Activity.</p>
<img src="images/figure31.png" alt="the new activity wizard">
<p>This brings up the new activity wizard (above). In this case, we have accepted the default activity name and ensured that the Launcher Activity box is checked.</p>
<p>Because the Launcher Activity button is checked, this will activity will represent the first screen that the user will see when the app is launched and so this is the primary activity. We can now click Finish.</p>
<p>This new activity is automatically registered in the manifest, but if view the manifest, we see a warning to the effect that the app is not indexable by Google search but we will select an Intent action and choose to ignore this warning.</p>
<p>In addition, both the original activity (MainActivity) and the new activity (Main2Activity) are marked as Launcher Activities. To resolve this, we will delete the Intent filter from the original activity and add a new attribute called parentActivityName and set it to Main2Activity with:</p>
<pre class="inset">
android:parentActivityName=".Main2Activity"&gt;</pre>
<p>So now we have identified Main2Activity as the primary activity and MainActivity as the secondary activity. We can now add some action to this by setting the app up so that when the user clicks on the floating action button, he (or she) will be taken to the secondary activity screen.</p>
<p>If we look at the code for Main2Activity (that is, the file Maun2Activity.kt) we can see that there is a setOnClickListener function that currently holds some default code which we will delete and in its place, we will insert an Intent object. We will pass two values to the constructor and these are a package context (represented by this) and a the class of the activity we want to navigate to and that is given as MainActivity::class.java.</p>
<p>Just a reminder that we are using Kotlin syntax for this so this would look a little different if we were coding in Java.</p>
<p>The next thing we want to do is to call a function called StartActivity which takes one argument, and that argument will be the Intent object we created and once the code has been added, the code for setOnClickListener will look like this.</p>
<pre class="inset">
fab.setOnClickListener { view -&gt;
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}</pre>
<p>Now we can run the application and when it starts, we can see the screen for Main2Activity and clicking the floating action button calls up the screen for MainActivity which displays a monster image! We can also press the phone’s back button to go back to the main activity and press it again, to go back to the Launcher screen.</p>
<p>There are newer approaches to managing navigation between screen including the Navigation Architecture component which is described more fully in the course, Android Development: The Navigation Architecture Component. This is a worthwhile course for new Android developers, but it is also useful to be able to understand the lower level approach shown here.</p>
<p>There will be times when you want manage navigation yourself using your own intents.</p>
<h2 class="sectiontitle">Send an Action to a New Activity</h2>
<p>When an activity is loaded with an intent as we saw previously, there are a number of ways of sharing data with the new activity.</p>
<p>We are starting with an app that has a simpler (in terms of code) main activity but four buttons have been added to the layout file (which is shown below) four buttons have been added.</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;androidx.constraintlayout.widget.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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main"
tools:context=".MainActivity"&gt;
&lt;TextView
android:id="@+id/instruction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/choose"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textStyle="bold"
android:textSize="24sp"
android:layout_marginBottom="16dp"/&gt;
&lt;LinearLayout
android:id="@+id/layout1"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/instruction"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:orientation="horizontal"
android:layout_marginBottom="16dp"&gt;
&lt;ImageButton
android:id="@+id/monster01"
android:contentDescription="@string/choose"
android:src="@drawable/monster01"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_weight="1"
android:scaleType="fitXY"/&gt;
&lt;ImageButton
android:id="@+id/monster02"
android:contentDescription="@string/choose"
android:src="@drawable/monster02"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_weight="1"
android:scaleType="fitXY"/&gt;
&lt;/LinearLayout&gt;
&lt;LinearLayout
android:id="@+id/layout2"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/layout1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:orientation="horizontal"&gt;
&lt;ImageButton
android:id="@+id/monster03"
android:contentDescription="@string/choose"
android:src="@drawable/monster03"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_weight="1"
android:scaleType="fitXY"/&gt;
&lt;ImageButton
android:id="@+id/monster04"
android:contentDescription="@string/choose"
android:src="@drawable/monster04"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_weight="1"
android:scaleType="fitXY"/&gt;
&lt;/LinearLayout&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</pre>
<p>As the content_main.xml file shows, the four buttons have been added to a LinearLayout and they are a particular kind of component called an image button. Each has an id of monter_01, monster_02 and so on and this is also the filename as seen in the source (src) attribute.</p>
<p>The intention here is that when the user clicks on one of the buttons, the app will jump to the detail screen which will display the image for the selected monster full-screen.</p>
<p>To implement this, we will refer to the id of each button in the main function (that is, in MainActivity.kt) and we will do this in the onCreate function. This is the state of the onCreate function before these changes are made.</p>
<pre class="inset">
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
}</pre>
<p>Starting with monster01, we will add the following line of code:</p>
<pre class="inset">
monster01.setOnClickListener {viewMonsterImage(R.drawable.monster01)}</pre>
<p>Note that the resource id has been generated automatically and we are calling onClickListener on this and passing our method name to it. In this case, the function we are using, viewMonsterImage(), to which we are passing the id of the monster image, is a custom function that has not been written yet. So we can use an intent action to generate this function.</p>
<p>We will start by creating an instance of Intent. We will pass in this as the context and the class of the activity we want to load:</p>
<pre class="inset">
val intent = Intent(this, DetailActivity::class.java)</pre>
<p>Since the viewMonsterImage function has been created for us, it has taken monster01 as an argument and we want to generalise the function so we will change this to monsterID. Note that we had been using monsterID in the auto-generated function hence monster01 was being passed as an int value since it was the id rather than the image we were passing in.</p>
<p>Now, we want to add an action to intent with:</p>
<pre class="inset">
intent.setAction(Intent.ACTION_VIEW)</pre>
<p>Note that an action is a string and typically you use a constant value that’s defined in the Intent clas. Then we call startActivity and pass it our intent object with:</p>
<pre class="inset">
startActivity(intent)</pre>
<p>The completed viewMonsterImage is shown here.</p>
<p>Just an interesting aside here, when we were typing ACTION_VIEW, as usual, a list of suggestions appears but this is a very long list and ACTION_VIEW, as you might expect, is near the bottom. However, if you type A followed by V or VI, IntelliJ seems to recognise that you want ACTION followed by a word starting V or VI so it jumps to that part of the list. So this is a handy way of accessing a suggestion without having to scroll down to the bottom of a very long list!</p>
<p>Next, we will call up the DetailActivity.kt file. We can access this through the navigation panel or use another handy IntelliJ shortcut which is Shift Shift and this opens up the search anywhere panel. We can type Detail in the Search box and then select the file we want from the search results.</p>
<p>In the onCreate function (of DetailActivity.kt) we will log the received action using the Log class, and a function of that class called i for information. This takes two parameters, a tag and a message. The tag is “Intents” and this is used to filter the Logcat messages in Android Studio. For the message, we “Action = “ a dollar sign followed by a pair of curly braces. Inside the curly braces we have intent.action. So this line of code is:</p>
<pre class="inset">
Log.i("Intents", "Action= ${intent.action}")</pre>
<p>This syntax would be more verbose in Java where you would use get intent and get action as method calls, but Kotlin allows you to use this more compact simple property syntax.</p>
<p>We can now run the app and see that it works pretty much as expected although I notice that whichever button I click, the image shown full screen is always monster01 and in the video, when the app is running, only the button for monster01 is clicked.</p>
<p>When I switch to the branch for 04_07e, I note that clicking on the button for monster01 works as expected, but in the course, no event listeners were added for the other buttons so clicking on them doesn’t do anything!</p>
<p>Going back to Android Studio, we can click on the Logcat tab in the bottom left to see what is happening when the app is executed. Note that there is what looks like a search box here, but it would be more accurate to consider it to be a filter. If we type in intents here, we will only see logged messages which include this term and we can see that the action has been passed over to DetailActivity.</p>
<h2>Send Data with URIs and Extras with Intents</h2>
<p>Previously we say how it is possible to pass an action over when starting a new activity with an intent but here, we will look at how it is possible to pass over much more detailed data. We can do this by using either the data object of the Intent or by passing data extras.</p>
<p>The URI (Uniform Resource Identifier) is a single property and it is strongly typed. In the main activity class, just before startActivity, we will create a URI object which we call uri – note that this is being created from a Java class (from Android.net). We then call the parse function and pass it a uriString which looks like a URL. It starts with “http://” and is followed by the base package. You can then add one or more virtual directory names and these constitute the action you want to pass and you can add a query string. Taking these in turn, the string is built up like this:</p>
<pre class="inset">
• http:// - this is our starting point
• http://com.example.myfirstapp – the package name has been added
• http://com.example.myfirstapp/view - this is the action we want to pass over
• http://com.example.myfirstapp/view?id=monsterid – and this is our query string</pre>
<p>So the uri is created with the line of code:</p>
<pre class="inset">
val uri = Uri.parse("http://com.example.myfirstapp/view?id=monsterid")</pre>
<p>Note that we are passing a uriString object to parse so it is wrapped in double quotes.</p>
<p>Next, we want to add the uri we created as the data property of the Intent object which we do with:</p>
<pre class="inset">
intent.data = uri</pre>
<p>In DetailView.kt, we will receive the uri from MainActivity.kt. We will then find out what the action is by using something known as the lastPathSegment of the data object.</p>
<p>We will create a variable called lastPart and assign it the value of lastPathSegment which is a property of data which is, in turn, a property of Intent, or at least this is how it looks based on the syntax so let’s check that.</p>
<p?In the Intent class, there is a property called ATTR_DATA which is a constant string value, data</p>
<pre class="inset">
public class Intent implements Parcelable, Cloneable {
private static final String ATTR_ACTION = "action";
private static final String TAG_CATEGORIES = "categories";
private static final String ATTR_CATEGORY = "category";
private static final String TAG_EXTRA = "extra";
private static final String ATTR_TYPE = "type";
private static final String ATTR_COMPONENT = "component";
private static final String ATTR_DATA = "data";
private static final String ATTR_FLAGS = "flags";</pre>
<p>In any case, the assignment of the value to lastPart looks like this:</p>
<pre class="inset">
val lastPart = intent.data?.lastPathSegment</pre>
<p>Note that data is defined as nullable. Next, we want to check if our action is view and if it is, execute the appropriate code so we will use a conditional statement.</p>
<pre class="inset">
if (lastPart!!.equals("view")) {
val monsterId = intent.data?.getQueryParameter("id")
Log.i("Intents", "Query parameter = $monsterId")
}</pre>
<p>Note that in the condition, we have !! after lastPart. This is an assertion that the value of lastPart is not null.</p>
<p>If the condition evaluates to true, we are creating a new variable called monsterId and to determine its value, we will extract the monsterId from data using a getQueryParameter function to which we will pass the string, id. Note that we are doing this with a safe call so this code will not execute if intent.data returns a null value.</p>
<p>Again, we will log some information to the Logcat window.</p>
<pre class="inset">
package com.example.myfirstapp
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
monster01.setOnClickListener{viewMonsterImage(R.drawable.monster01)}
}
private fun viewMonsterImage(monsterId: Int) {
val intent = Intent(this, DetailActivity::class.java)
intent.setAction(Intent.ACTION_VIEW)
val uri=Uri.parse("http://com.example.myfirstapp/view?id= $monsterId")
intent.data = uri
startActivity(intent)
}
}</pre>
<p>The MainActivity.kt file</p>
<pre class="inset">
package com.example.myfirstapp
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_detail.*
import kotlinx.android.synthetic.main.content_detail.*
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
setSupportActionBar(toolbar)
Log.i("Intents", "Action = ${intent.action}")
val lastPart = intent.data?.lastPathSegment
if (lastPart!!.equals("view")) {
val monsterId = intent.data?.getQueryParameter("id")
Log.i("Intents", "Query parameter = $monsterId")
}
}
}</pre>
<p>The DetailActivity.kt file</p>
<p>For reference, the current state of the MainActivity.kt and DetailActivity.kt files are shown in above.</p>
<p>So, here we have used a query parameter to pass data between activities and we can add as many of these as are needed to pass all the data required.</p>
<p>Another way to pass information between activities is by using Intent extras. These are kry value pairs where the key is a string and the associated value is strongly typed. It can be a string, a number or any primitive type supported by Java and Kotlin.</p>
<p>Passing the data is very simple. In MainActivity.kt, we just need to call putExtra on the Intent we had created and we do this with:</p>
<pre class="inset">
intent.putExtra("monsterId", monsterId</pre>
<p>In this case, the mosterId we are passing as a value is the same monsterId that was passed as an argument to the viewMonsterImage function. You may also notice that there are a large number of versions of the putExtra function, one for each of the supported data types but in this case, the type is inferred from the value we are passing in.</p>
<p>To receive the data in DetailActivity.kt, we will create a variable called extraId and use the getInt function, using the same key of “monsterId” that we added to the Intent in MainActivity.kt and the syntax for this is:</p>
<pre class="inset">
val extraId = intent.extras!!.getInt("monsterId")</pre>
<p>Again, we are asserting that intent.extras does not return a null value because we cannot retrieve any data if this is the case (this would mean that there are no extras for us to query).</p>
<p>We will also log this on the Logcat window with:</p>
<pre class="inset">
Log.i("Intents", "Extra value = $extraId")</pre>
<p>So we have managed to pass the monsterId over to the ActivityDetail activity but as yet, we are not doing anything with it. What we want to do is to use this value to dynamically load the selected image.</p>
<p>Let’s take a look at the activity layout which we can access by following these steps:</p>
<pre class="inset">
• In the DetailActivity.kt file, hold control and click on the layout in the line
o setContentView(R.layout.activity_detail)
• This calls up the file activity_detail.xml and from here, we want to control click on the included layout in
o &lt;include layout="@layout/content_detail"/&gt;
• And this calls up the file, content_detail.xml.
&lt;ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/monster01"
android:id="@+id/monsterImage"
android:contentDescription="@string/my_favorite_monster"
app:layout_constraintTop_toBottomOf="@+id/headline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="8dp"/&gt;</pre>
<p>The fragment of code from the content_detail.xml above shows the ImageView element found in this file. Note that this ImageView element has an id of monsterImage.</p>
<p>Back in DetailActivity.kt, note that we have an import statement for the layout file so we can directly reference the monsterImage object. We will call a function from monsterImage called setImageResource and we will pass this the value extraId:</p>
<pre class="inset">
monsterImage.setImageResource(extraId)</pre>
<p>You may have noticed that in MainActivity.kt, we set an onClickListener for the monster01 image, but not for the others and so our app, so far, only had the ability to display this image full screen. Now that we are using a simple method to pass our monsterId over to DetailActivity.kt and used it to set the full screen image to any of the selected images, this will work for any of the images provided that they have the same onClickListener set so we will now add these.</p>
<p>And if we run the application again, we can now select any of the images and they will be displayed full screen. So now we are allowing the user to interactively select an image they want to see in full screen.</p>
<p>We can pass any sort of data between activities and as we have seen, we can do this in three different ways:</p>
<pre class="inset">
• Using actions
• Using URIs as data
• Using Intent extras</pre>
<p>As a final reference for this section, figures 40 and 41 show the final versions of the MainActivity.kt and DetailActivity.kt files.</p>
<pre class="inset">
package com.example.myfirstapp
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
monster01.setOnClickListener {viewMonsterImage(R.drawable.monster01)}
monster02.setOnClickListener {viewMonsterImage(R.drawable.monster02)}
monster03.setOnClickListener {viewMonsterImage(R.drawable.monster03)}
monster04.setOnClickListener {viewMonsterImage(R.drawable.monster04)}
}
private fun viewMonsterImage(monsterId: Int) {
val intent = Intent(this, DetailActivity::class.java)
intent.setAction(Intent.ACTION_VIEW)
val uri = Uri.parse("http://com.example.myfirstapp/view?id=$monsterId")
intent.data = uri
intent.putExtra("monsterId", monsterId)
startActivity(intent)
}
}</pre>
<p>The final version of MainActivity.kt for this section</p>
<pre class="inset">
package com.example.myfirstapp
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_detail.*
import kotlinx.android.synthetic.main.content_detail.*
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
setSupportActionBar(toolbar)
Log.i("Intents", "Action = ${intent.action}")
val lastPart = intent.data?.lastPathSegment
if (lastPart!!.equals("view")) {
val monsterId = intent.data?.getQueryParameter("id")
Log.i("Intents", "Query parameter = $monsterId")
}
val extraId = intent.extras!!.getInt("monsterId")
Log.i("Intents", "Extra value = $extraId")
monsterImage.setImageResource(extraId)
}
}</pre>
<p>The final version of DetailActivity.kt for this section</p>
<h2 class="sectiontitle">Handle Shared Data with an Intent Filter</h2>
<p>Passing data between activities in the same application is relatively straightforward because we know the names of the activities and classes within the app and so these can be specified explicitly and for this reason, we refer to these as explicit intents.</p>
<p>When data is passed between applications, it does not know which activity or application is going to handle it. An example of this would be, for instance, where you click on a link to a webpage from inside an app that does not handle web pages, for instance a link embedded within a Word document, this intent would be handled by an app that has registered an ability to handle this type of data – in other words, a web browser.</p>
<p>Your own application can register to handle these kinds of intents and this is done in the application manifest. To demonstrate this, we will register the app from the previous section to handle simple text data from other applications which we will translate into a request to display a particular image.</p>
<p>In the manifest file, we have already registered the activity we called DetailActivity and as a reminder, this declaration is</p>
<pre class="inset">
&lt;activity
android:name=".DetailActivity"
android:label="@string/my_favorite_monster"
android:theme="@style/AppTheme.NoActionBar"
android:parentActivityName=".MainActivity"/&gt;</pre>
<p>The DetailActivity as registered in our manifest (AndroidManidest.xml)</p>
<p>We will start here by turning the DetailActivity declaration into an opening and closing tag and then copying the intent filter from MainActivity so that we now have the modified DetailActivity.</p>
<pre class="inset">
&lt;activity
android:name=".DetailActivity"
android:label="@string/my_favorite_monster"
android:theme="@style/AppTheme.NoActionBar"
android:parentActivityName=".MainActivity"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;</pre>
<p>The modified DetailActivity.</p>
<p>As before, of course, we can’t have two LAUNCHER activities but we will amend these as follows:</p>
<pre class="inset">
&lt;action android:name="android.intent.action.MAIN"/&gt;</pre>
<p>Becomes</p>
<pre class="inset">
&lt;action android:name="android.intent.action.SEND"/&gt;</pre>
<p>SEND equates to a constant in the intent class of action_set and when any application sends simple text for handling by another application, the action is always SEND.</p>
<p>And</p>
<pre class="inset">
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;</pre>
<p>becomes </p>
<pre class="inset">
&lt;category android:name="android.intent.category.DEFAULT"/&gt;</pre>
<p>Next, I need to indicate what type of data I want to receive. We will create a data element and set it’s mimeType attribute to “text/plain” and this is effectively a declaration that if an app on the device sends simple text, my app is able to handle it.</p>
<p>Now, we want to go to the DetailActivity.kt file and just before our first line of code that logs an intent, we will add some code to examine the intent action to see if it matches ACTION_SEND. We will put this in an if statement but we aren’t doing anything else with the text at the moment so if there is a match, we will execute a simple return and this gives us the code shown below.</p>
<pre class="inset">
if(intent.action == Intent.ACTION_SEND) {
val monster = intent?.getStringExtra(Intent.EXTRA_TEXT)
Log.i("Intents", "You selected monster $monster")
return
}</pre>
<p>Now, if we run the application on our virtual device (I an running it on a Pixel 2 device) we should be able to send text to our app. I have installed keep (a simple note-taking app) on the device and if I select Send and then Send via other apps, I can see that our app is displayed as one of the apps that we are able to send this data to.</p>
<p>If we select our app, we will jump to the Detail Activity because we have not provided any code yet to handle this text.</p>
<p>We will go back to DetailActivity.kt and add some code before our return statement. When our app receives the text (for example, from Keep) it arrruves as a StringExtra with a key of extra_text and that is a constant of the Intent class. So we will create a variable called monster and we will use the intent’s getStringExtra function to return the StringExtra with:</p>
<pre class="inset">
val monster = intent?.getStringExtra(Intent.EXTRA_TEXT)</pre>
<p>We will also log this and the message will be “You selected monster…” followed by the text passed to our app and the code for this is:</p>
<pre class="inset">
Log.i("Intents", "You selected monster $monster")</pre>
<p>We will run the application again, and once again send our text (note that the text we are sending is monster01) and again, we will see that our app is not really doing anything with the text it has received. However, we can see in Logcat the text that we received and it is what we were expecting. The output in the Logcat window below.</p>
<img src="images/figure45.png" alt="">
<p>Now, we want to use the text we receive to retrieve the corresponding resource ID so we will create a new variable called monsterId. To obtain a value for monsterId, we will use an expression which starts with resources and then calls a function called getIdentifier. The getIdentifier takes three functions and these are:</p>
<pre class="inset">
• The variable which is monster in this case, and we will call the function trim on this because it may have a trailing hard return or extra space
• Next is the type of resource which is drawable.
• The final argument is the package name which is the location in he resources class where the resource is stored.</pre>
<p>The resulting line of code is:</p>
<pre class="inset">val monsterId = resources.getIdentifier(monster?.trim(), "drawable", packageName)</pre>
<p>Since we now have the resource ID, we can call setImageResource just as we did in a previous exercise and pass it that ID. And the line of code to do that is:</p>
<pre class="inset">
monsterImage.setImageResource(monsterId)</pre>
<p>We will retain the return statement because this passes control back after the code has been executed and note that this code only executes when the app is sent some simple text by an external app.</p>
<p>Now, we can run the app again and pass text over to our app and if it corresponds to one of our four resource IDs, the appropriate monster image is displayed full screen. Note that we had indicated that this data is nullable so if we send in some text that does not correspond to one of the resource ID, we simply see a white screen.</p>
<p>So now we can see that the app will receive and handle plain text sent from any other app, but what it does with the text is determined solely by the code in our app.</p>
<p>To finish off, I will reproduce the important files from this app.</p>
<pre class="inset">
package com.example.myfirstapp
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
monster01.setOnClickListener {viewMonsterImage(R.drawable.monster01)}
monster02.setOnClickListener {viewMonsterImage(R.drawable.monster02)}
monster03.setOnClickListener {viewMonsterImage(R.drawable.monster03)}
monster04.setOnClickListener {viewMonsterImage(R.drawable.monster04)}
}
private fun viewMonsterImage(monsterId: Int) {
val intent = Intent(this, DetailActivity::class.java)
intent.setAction(Intent.ACTION_VIEW)
val uri = Uri.parse("http://com.example.myfirstapp/view?id=$monsterId")
intent.data = uri
intent.putExtra("monsterId", monsterId)
startActivity(intent)
}
}</pre>
<p>MainActivirt.kt</p>
<pre class="inset">
package com.example.myfirstapp
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import kotlinx.android.synthetic.main.activity_detail.*
import kotlinx.android.synthetic.main.content_detail.*
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
setSupportActionBar(toolbar)
if(intent.action == Intent.ACTION_SEND) {
val monster = intent?.getStringExtra(Intent.EXTRA_TEXT)
Log.i("Intents", "You selected monster $monster")
val monsterId = resources.getIdentifier(monster?.trim(), "drawable", packageName)
monsterImage.setImageResource(monsterId)
return
}
Log.i("Intents", "Action = ${intent.action}")
val lastPart = intent.data?.lastPathSegment
if (lastPart!!.equals("view")) {
val monsterId = intent.data?.getQueryParameter("id")
Log.i("Intents", "Query parameter = $monsterId")
}
val extraId = intent.extras!!.getInt("monsterId")
Log.i("Intents", "Extra value = $extraId")
monsterImage.setImageResource(extraId)
}
}</pre>
<p>DetailActivity.kt</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="com.example.myfirstapp"&gt;
&lt;application
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" tools:ignore="GoogleAppIndexingWarning"&gt;
&lt;activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;activity
android:name=".DetailActivity"
android:label="@string/my_favorite_monster"
android:theme="@style/AppTheme.NoActionBar"
android:parentActivityName=".MainActivity"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.SEND"/&gt;
&lt;category android:name="android.intent.category.DEFAULT"/&gt;
&lt;data android:mimeType="text/plain"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;/application&gt;
&lt;/manifest&gt;</pre>
<p>AndroidManifest.xml</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DetailActivity"&gt;
&lt;com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay"&gt;
&lt;androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/&gt;
&lt;/com.google.android.material.appbar.AppBarLayout&gt;
&lt;include layout="@layout/content_detail"/&gt;
&lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&gt;</pre>
<p>ActivityDetail.xml</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;androidx.constraintlayout.widget.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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_detail"
tools:context=".DetailActivity"&gt;
&lt;TextView
android:id="@+id/headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_favorite_monster"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="30dp"
android:textSize="36sp"/&gt;
&lt;ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/monster01"
android:id="@+id/monsterImage"
android:contentDescription="@string/my_favorite_monster"
app:layout_constraintTop_toBottomOf="@+id/headline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="8dp"/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</pre>
<p>ContentDetail.xml</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='fundamentals .html';">
Android Development Fundamentals
</button>
<button class="button" onclick="window.location.href='gettingstarted.html';">
Getting Started
</button>
<button class="button" onclick="window.location.href='exploring.html';">
Exploring Android Projects
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 489 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 556 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 638 KiB

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 220.2 266.6" style="enable-background:new 0 0 220.2 266.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#C0E0E6;}
.st1{fill:#A5D2DB;}
.st2{fill:#F0EFF4;}
.st3{fill:#413C57;}
.st4{fill:none;stroke:#8AA5C4;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st5{fill:#8AA5C4;}
.st6{fill:none;stroke:#D9D9E2;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st7{fill:none;stroke:#2C2F44;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<path class="st0" d="M31,12.4C31.3,5,60.6-1.3,75.5,6s43.6,20.7,51.6,36.9s17.9,22.9,22.2,21.9l-9.9,7c0,0,49.5,118,25.6,170.5
S4.8,245.5,4.8,245.5s81.5,4.3,66.5-78.8S48.3,32.1,39.6,22.2S30.6,19.7,31,12.4z"/>
<g>
<path class="st0" d="M150.1,102.4c0,0,25.5,61.9,42.1,52.7c16.5-9.2-14.2-52.6,0-60.8s28.1,6.9,28.1,6.9s-17.2-6.9-15.2,8.9
c2,15.9,26.5,63.8,1,72.4S160.5,166,160.5,166l-0.1-0.2C147.3,147.3,143.5,123.9,150.1,102.4L150.1,102.4z"/>
</g>
<path class="st1" d="M152.6,108.1c-1.6-3.5-2.5-5.7-2.5-5.7c-6.6,21.5-2.8,44.9,10.3,63.4l0.1,0.2c0,0,3.1,3.8,8.4,8
C165.3,150.6,158.6,126.8,152.6,108.1z"/>
<g>
<path class="st0" d="M91.4,135.8c2.9,6.8-1,61.7-49.1,66.1c-5.7,0-23-17-32.1,2.7c0,0-11.3-22.4,14.3-24c25.7-1.7,46-8.5,46.8-61.8
C85.5,114.3,88.4,129,91.4,135.8z"/>
<path class="st0" d="M91.4,135.8c2.9,6.8-1,61.7-49.1,66.1c-5.7,0-23-17-32.1,2.7c0,0-11.3-22.4,14.3-24c25.7-1.7,46-8.5,46.8-61.8
C85.5,114.3,88.4,129,91.4,135.8z"/>
</g>
<path class="st1" d="M71.3,118.8c-0.2,12-1.3,21.6-3.3,29.3c1.1,6,2.2,12.2,3.3,18.6c1.5,8.1,2,15.3,1.8,21.8
c19-18,20.4-47.8,18.3-52.7C88.4,129,85.5,114.3,71.3,118.8z"/>
<polygon class="st2" points="80.7,84.2 89.7,104.5 89.7,85.9 "/>
<path class="st3" d="M89.5,53.1c1.4-6.8-4.9-13-11.7-11.4c-3,0.7-4.5,2.7-3,5.9c3,6.3,13.7,10.3,14.7,5.7
C89.5,53.2,89.5,53.2,89.5,53.1z"/>
<path class="st3" d="M110.3,34.2c-2.5-4.3-15-2.6-9.3,5.5S115.3,42.9,110.3,34.2z"/>
<path class="st3" d="M90.2,30.8c6.6-2.8,3.1-13-3.8-11c-1.4,0.4-2.4,1.1-2.7,1.9c-1,2.6,1.1,10.8,5.6,9.5
C89.6,31,89.9,30.9,90.2,30.8z"/>
<path class="st4" d="M65.6,154.1c-0.8-4.6-1.6-9.1-2.4-13.5C51,71.9,43.8,29.5,36,20.6c-8.7-9.9-9-2.5-8.7-9.9
C27.7,3.3,57-3.1,72,4.2s43.7,20.7,51.7,37s18,23,22.3,22l-10,7c0,0,49.7,118.3,25.7,171S1,244.6,1,244.6s65,3.5,68.4-55"/>
<path class="st4" d="M146.6,98.8c0,0,25.7,62.4,42.4,53.1c16.7-9.3-14.3-53,0-61.3s28.3,7,28.3,7s-17.3-7-15.3,9s26.7,64.3,1,73
c-15.7,5.3-29.5-2.2-37.7-8.7"/>
<g>
<path class="st5" d="M88.7,133.3c-0.2,7.5-1.3,15-3.1,22.3c-1.9,7.3-4.6,14.4-8.6,20.9c-2,3.2-4.3,6.3-6.9,9.1s-5.6,5.2-8.8,7.3
c-6.4,4.2-14,6.4-21.6,7.2h-0.1c-1,0-1.8-0.3-2.6-0.6s-1.5-0.6-2.2-1l-4.2-2.1c-2.8-1.3-5.6-2.5-8.6-2.9c-2.9-0.5-5.9,0.1-8.2,1.8
c-2.4,1.7-4,4.3-5.3,7l0,0c-0.2,0.5-0.8,0.7-1.3,0.5c-0.2-0.1-0.4-0.3-0.5-0.5c-1.2-2.5-1.9-5-2.3-7.7s-0.3-5.5,0.6-8.1
c0.9-2.7,2.9-4.9,5.2-6.3c2.3-1.5,5-2.2,7.6-2.7c0.7-0.1,1.3-0.2,2-0.3l2-0.2l3.9-0.3c2.6-0.2,5.1-0.5,7.6-0.9
c5-0.8,10-2.1,14.5-4.6c2.3-1.2,4.2-2.7,6.1-4.4l1.3-1.4c0.4-0.5,0.9-0.9,1.3-1.4c0.8-1,1.6-2,2.2-3.1c0.7-1.1,1.4-2.1,1.9-3.3
c0.6-1.1,1.2-2.3,1.6-3.5c1-2.4,1.8-4.8,2.5-7.3c2.7-9.9,3.5-20.3,3.8-30.7c0.1,5.2,0,10.4-0.5,15.5c-0.4,5.2-1.2,10.3-2.4,15.4
c-0.6,2.5-1.4,5-2.4,7.4c-0.4,1.2-1,2.4-1.6,3.6c-0.5,1.2-1.2,2.3-1.9,3.4c-0.6,1.2-1.5,2.2-2.3,3.2c-0.4,0.5-0.8,1-1.3,1.5
l-1.3,1.5c-2,1.8-4,3.5-6.4,4.7c-2.3,1.4-4.8,2.3-7.3,3.2c-2.5,0.8-5.1,1.4-7.7,1.8c-2.6,0.5-5.2,0.7-7.8,1l-3.9,0.3l-1.9,0.2
c-0.6,0.1-1.2,0.2-1.9,0.3c-2.5,0.5-4.9,1.2-6.9,2.5c-2.1,1.3-3.7,3.1-4.4,5.4c-0.8,2.2-0.9,4.8-0.5,7.2s1.1,4.9,2.2,7.1H6.5
c0.7-1.5,1.4-2.9,2.4-4.2s2.1-2.6,3.5-3.5c1.4-1,3-1.7,4.6-2c1.7-0.3,3.4-0.3,5-0.1c3.3,0.5,6.3,1.8,9.1,3.2l4.2,2.1
c0.7,0.3,1.4,0.7,2.1,0.9c0.7,0.3,1.4,0.5,1.9,0.5h-0.1c7.3-0.7,14.6-2.8,20.9-6.8c6.3-3.9,11.5-9.4,15.5-15.7s6.8-13.3,8.9-20.5
c1-3.6,1.9-7.3,2.5-11C88,140.8,88.5,137,88.7,133.3z"/>
</g>
<polygon class="st6" points="79.7,83.2 88.7,103.6 88.7,85 "/>
<path class="st4" d="M59.7,72.2c5.7,5.5,35.8,30.2,86.3-9"/>
<path class="st7" d="M88.7,53.1c1.4-6.8-4.9-13-11.7-11.4c-3,0.7-4.5,2.7-3,5.9c3,6.3,13.7,10.3,14.7,5.7
C88.7,53.2,88.7,53.2,88.7,53.1z"/>
<path class="st7" d="M110.3,35.9c-2.5-4.3-15-2.6-9.3,5.5S115.3,44.6,110.3,35.9z"/>
<path class="st7" d="M88.5,30.8c6.6-2.8,3.1-13-3.8-11c-1.4,0.4-2.4,1.1-2.7,1.9c-1,2.6,1.1,10.8,5.6,9.5
C87.9,31,88.2,30.9,88.5,30.8z"/>
<g>
<path class="st5" d="M67.7,65.1c-2,2.2-4.1,4.1-6,6c-1,1-2,2-2.8,3c-0.9,1.1-1.7,2.2-2.5,3.4c0-1.5,0.5-3,1.2-4.3s1.7-2.5,2.7-3.6
s2.2-2,3.4-2.8C64.9,66.2,66.2,65.5,67.7,65.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 520 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 626 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 503 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 475 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 423 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 335 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 651 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 329 KiB

@ -0,0 +1,323 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2019</h2>
<h2 class="episodetitle">Exploring Android Projects</h2>
</div>
<article>
<h2 class="sectiontitle">Check Out the Exercise Files on GitHub</h2>
<p>A GitHub account is not required to download the exercise files because the repository is set to public, but there are a lot of components and examples available there so it is a worthwhile thing to have.</p>
<p>The GitHub url for the exercise files is:</p>
<pre class="inset">
<a href="https://github.com/davidgassner/AndroidDev2019FirstApp">https://github.com/davidgassner/AndroidDev2019FirstApp</a></pre>
<p>The procedure is to click on the Clone or Download button, click the clipboard icon to copy the url, go to Android Studio and select Check out project form version control on the welcome screen.</p>
<p>From here, select Git, paste in the url and click test to make sure the connection has been made successfully. Assuming it has, you then click Clone and then yes to confirm.</p>
<p>Side note, I had problems cloning the files via ssh but switched to downloading via https and this seems to have worked.</p>
<p>There are two ways to switch to a different branch. You can either select the VCS menu followed by Git and then branches to display a list of branches or select the Git Master in the bottom right and then show more branches and this does the same thing.</p>
<p>When you select a branch, you will see a new branch name suggested. Click OK and then, if asked, click Force Checkout. Sometimes, you may see problems such as unresolved references which can be fixed by refreshing the Gradle project. You do this by clicking on the Gradle tab on the right-hand side or the Gradle icon (which is a small elephant) on the toolbar (the tooltip is Sync Project with Gradle files (see figure 1) and this should resolve the problems.</p>
<img src="images/figure1.png" alt="the option to sync the project with the Gradle files">
<p>For further information, the Gradle documentation can be found in the online <a href="https://docs.gradle.org/current/userguide/userguide.html">Gradle Documentation</a>.
</p>
<p>At the end of each exercise, you should check your changes in to the local repository before checking out the next exercise file. To do this, click the Version Control tab in the bottom left (which was not visible on my system at the time of trying the exercise) or select Commit from the VCS menu.</p>
<p>One advantage of doing this via the VC tab is that you will see a list of changed files and you can click Control + D to being up a window showing the two versions of that file side by side and from here you can click on Commit. You may also see some errors here so you have the option of reviewing them before committing.</p>
<p>Note that in order to commit changes, you are required to provide some sort of commit messages to describe the version.</p>
<h2 class="sectiontitle">Explore the Project Structure</h2>
<p>You will see, with Android Studio, that the structure of files and directory names for a project is relatively complex but standard. Files can be accessed via the project window to the left of the screen and this window can be opened and closed by pressing Control + 1 (although this doesn’t seem to work on my system). </p>
<p>Note that the project window includes multiple scopes. The project scope shows you all your applications files and folders as they appear on the disc and the other scopes files this data in different ways. The Android scope, for example, only shows you the files and folders you typically use the most while developing applications. </p>
<p>Note that the default option seems to be the Android scope and this is shown in a drop-down box at the top of the window. As you might expect, the drop-down box gives you access to the other scopes. </p>
<p>If we look at the project scope, one thing to note is that some directories are prefixed with a full stop and this indicates that the directories contain configuration files. These are .gradle for the Gradle plug in and .idea for the underlying IntelliJ Idea environment.</p>
<p>The source directory is under the app directory and this is where you put your code and resources for the application. </p>
<p>The app directory is a module and projects in Android Studio can contain multiple modules. Within the source directory is a directory called Main and within this, a directory called Java and this is where the code and resources for your application live. Note that this directory is also called Java even if you are coding in Kotlin. </p>
<p>Alongside the Java folder is the res folder and this contains resources for the application such as image or xml files. Within this folder, typically, image files will be inside the drawable folder and xml files inside the values folder. These xml files define various resources such as colours, dimensions, strings (such as the name of the app) and styles. </p>
<p>Other folders within the source folder are androidTest (within this folder is an ExampleInstrumetedTest) and Test (similarly, within this folder you will find an ExampleUnitTest) and these are used to test the interface rather than to test business (or application) logic. </p>
<p>Inside the main directory, in addition to the java and res folders, there is a file called AndroidManifest.xml and this file contains the declarations for the activities and services that are critical to the application. </p>
<p>Here is a sample of this type of file and this one, as it happens, is taken from the exercise file for this part of the course. </p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstapp"&gt;
&lt;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"&gt;
&lt;activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;/application&gt;
&lt;/manifest&gt;</pre>
<p>Going back to Android Studio, we have been looking at files with the project scope, but it is recommended to use the Android scope in order to simplify the display. Everything you need should be shown there but it is also worth remembering that the option to switch back to the project scope is there if it is needed.</p>
<h2 class="sectiontitle">Manage Gradle Build Scripts</h2>
<p>Gradle is a build system that manages the compilation and packaging of your code so that it can be deployed through an app store such as Google Play.</p>
<p>Gradle is configured via files called build.gradle and when you first create an application, there are two of these, one labelled as the project file and one labelled as the module file. However, there is a known bug in Android Studio which results in possibly only one of these being displayed in the Android scope so it may be necessary to switch back to the Project scope to see both.</p>
<p>From the project scope, you will see a top-level file called build.gradle but note that it is not labelled as either the project file or the module file. Recall that the app directory is a module and inside this directory is another file called build.gradle (also not labelled). As you might expect, the file inside the module directory is the same as the one labelled module file in the Project scope and the top-level file is the one labelled as the project file in the Project scope.</p>
<pre class="inset">
// Top-level build file where you can add configuration options common to all sub-projects/modules.
build script {
ext.kotlin_version = '1.3.11'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0-alpha07'
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
}</pre>
<p>A sample Gradle build configuration file (project file)</p>
<pre class="inset">
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.myfirstapp"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.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'
implementation 'com.android.support:design:28.0.0'
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'
}</pre>
<p>A sample Gradle build configuration file (module file)</p>
<p>The files shown here are the Gradle build files and these are the project and module files respectively.</p>
<p>The project file defines the Gradle plugin version and also, if you are working in Kotlin, the Kotlin plugin version. Now, if you update either Android Studio or Kotlin after you have created a project, these numbers will no longer match and this will cause the build to fail.</p>
<p>To demonstrate this, I have closed the project and then from the welcome screen, selected check for updates (under the configure menu) and this has located an update to Android Studio which I have installed. When I restart Android Studio, there is now a discrepancy between the actual Gradle plugin version and the version number in the project file. This is reported in the dialog.</p>
<img src="images/figure5.png" alt="dialog box reporting a discrepancy with the Gradle plugin version number">
<p>Note that I can choose to either update by clicking the Update button or do the update manually later. I’m not sure why I might want to update manually but for the time being, note (from figure 3) that the plugin version had been reported as:</p>
<pre class="inset">
classpath 'com.android.tools.build:gradle:3.4.0-alpha07'</pre>
<p>and after the update, it is now reported as:</p>
<pre class="inset">
classpath 'com.android.tools.build:gradle:3.4.2'</pre>
<p>Performing a manual update seems straightforward enough if you know the version of the plugin but I’m not sure how you find this other than in the dialog box so I would either take a note of it or close and reopen the project in order to make the dialog box reappear if I wanted to do a manual correction to the configuration.</p>
<p>The app level file includes things like the version code which is always numeric and the version name which can be any string. The version code is what you use internally to track the version and the version name is what the user sees on the app store.</p>
<p>The version code should be incremented every time you upgrade the application but the version name only needs to be updated if this makes sense for the users.</p>
<p>Other important entries in the module file include:</p>
<pre class="inset">
• The application id which matches the base package where your Java and Kotlin classes are stored.
• The target SDK version which points to an API level.
• The minimum SDK version which indicates the oldest version of Android the app is approved for (currently Google recommends a minimum SDK of 16 because older versions of Android are no longer supported by the Google Play support libraries).
• Under dependencies there are strings representing different libraries your application depends on. These start with the word implementation which is followed by a string with the library name and version. When the application is built, Gradle will use these dependencies to identify which components the app needs and will obtain some of these from a local Maven repository and some from online repositories.</pre>
<p>The online Maven repositories are identified in the project in two places. The first is under repositories and the second is under allprojects &gt; repositories. As you can see in figure 3, there are two such repositories listed.</p>
<pre class="inset">
• google() points to Google’s own Maven repository.
• jcenter() reports to another open-source Maven library that is also available online.</pre>
<p>For more advanced Android apps, you will need to edit these. Most commonly you will edit the module level Gradle build file but occasionally you will also need to edit the project level file as well.</p>
<h2 class="sectiontitle">Manage the App Manifest File</h2>
<p>Typically, a new app that you create will have a single module but in a complete production application, it is normal to have one module for the app and then other modules for various libraries that support the app.</p>
<p>Each module has a manifest file which is always called AndroidManifest.xml and these are stored in the manifests directory. Note on this point, the file appears to be inside a directory when you are viewing the project under the Android scope rather than the Project scope which suggests that this is a “directory” created for organisational purposes under Android scope rather than a physical directory. For instance, if I look at the manifest file shown in the examples above, its actual location is:</p>
<pre class="inset">
C:\Users\emuba\Documents\AndroidDev2019FirstApp\app\src\main</pre>
<p>In other words, it is stored inside the main folder.</p>
<p>Recall that a sample AndroidManifest.xml file (which happens to be the same one referenced by the pathway shown above) is shown previously.</p>
<p>Some key points about this file are:</p>
<p class="inset">
• It is an XML file.
• Its root element is called manifest.
• It declares at least one namespace used to identify various attributes in the rest of the file.
• The package points to the base package for the application and this will match the package where you have stored your root classes such as MainActivity.
• Within the manifest is an application element which has some useful attributes such as label, icon, allowBackup and so on.
• There is also an activity element. In an Android app, each activity represents a different screen in the application and a typical app when created will have at least one activity. With the activity element:
o Name refers to the class that controls the behaviour of the activity. If you hold down the control key and click on the class name, you can jump to the actual class definition.
o The label can be displayed in a couple of places within the activity. Typically, it will appear at the top of the screen but if the activity is set to Main and the category to launcher, it will be displayed on the devices launcher screen associated with the launcher icon.</p>
<p>Each new activity or service in the application must be registered in the manifest. To see how this works, we will add a new activity to our application (the branch is now 03_04). This is done by right clicking on app, selecting new and then New and then Activity and in this case, I will select an Empty Activity.</p>
<p>I will then change the name to DetailActivity and accept all the other default settings and complete the process by clicking Finish and then clicking the button to add the file to Git.</p>
<p>Now, if I look at the manifest file again, I can see that it now has two elements, one of which is the newly added DetailActivity and this is empty.</p>
<p>If we do the same thing again but select Service rather than Activity, this time I will accept the default name of MyService and click Finish and add the file to Git, I can now go back to the manifest and see that this has also been registered. Figure 6 shows the manifest file again with these changes highlighted in yellow.</p>
<pre class="inset">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstapp"&gt;
&lt;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"&gt;
&lt;service
android:name=".MyService"
android:enabled="true"
android:exported="true"&gt;
&lt;/service&gt;
&lt;activity android:name=".DetailActivity"&gt;
&lt;/activity&gt;
&lt;activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;category android:name="android.intent.category.LAUNCHER"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;/application&gt;
&lt;/manifest&gt;</pre>
<p>The manifest file which is similar to the one shown in figure 2 but with the addition of the new activity (DetailActivity) and service (MyService).</p>
<p>Note that in addition to registering the activity and the service, classes are created for both of these and for the activity, and for the activity, an xml file has been created in the res folder under layout. Below, there is a snapshot of the project window displaying the location of these files and you will see that these are displayed under the Project scope.</p>
<img src="images/figure7.png" alt="Android Studio snapshot displaying the file locations for our new active and service classes and the activity xml file">
<p>When you deploy an Android app, the manifest is included and this allows the Android OS and application framework to examine the app to determine how to handle the app and its components. Understanding the manifest and how to maintain it is therefore a critical element of the process of creating apps for Android.</p>
<h2 class="sectiontitle">Use Dependencies and Support Libraries</h2>
<p>The Gradle build system is integrated into Android Studio and it depends on a system known as Maven. A Maven repository is a library of libraries and allows developers to share these libraries with others.</p>
<p>The dependencies (mentioned previously) that you declare in the Gradle build file point to Maven libraries. The variables determining the versions of various libraries are stored in the Project build file but the actual dependencies should be declared in the Module build file.</p>
<pre class="inset">
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'
implementation 'com.android.support:design:28.0.0'
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'
}</pre>
<p>To illustrate this, here is a copy of these dependencies taken from the Module build file we looked at earlier. Note that the strings defining these dependencies can be enclosed in single or double quotes where the dependency is a string literal but where the string includes a variable (which you can see, for instance, in the second dependency above which uses a variable to specify the Kotlin version), the string must be enclosed in double quotes.</p>
<p>Since these libraries are stored separately from the primary SDK, they may support older versions of Android. The third dependency in figure 8 shows a version number (v7) and this denotes the fact that this library is backward compatible as far as the level shown. In this example, the library is compatible with API level 7 and above.</p>
<p>There is a newer way to declare these dependencies and libraries using the newer style of declaration start with androidX rather than com.android.support. You can upgrade your app to the newer libraries by selecting the Refactor menu and then Migrate to AndroidX.</p>
<p>The changes that will be made are shown in a preview at the bottom of the screen and if you are happy to proceed, you can click on Do Refactor to complete the process.</p>
<p>These dependencies are the same as those shown above after the project has been migrated in this way.</p>
<pre class="inset">
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}</pre>
<p>With this change, we are now seeing a warning in the build file that states that a newer version of the AndroidX libraries are available (in the video this applies to all 4 libraries prefixed with android but on my system, I already have a newer version of the constraint layout library and this one does not show the warning so I can only see this on 3 of the libraries).</p>
<p>Theoretically, you can use an intention action to change this to the latest library but this didn’t work on my install but there are two ways round this. It is possible to click on the drop-down box displaying the warning light bulb and select “Upgrade to….” followed by the correct version number. This number is also shown in the full warning message so a second option would be to manually change the version number.</p>
<p>However, the version numbers are updated, you will then need to re-sync the Grade files (this is confirmed by a message at the top of the screen) and you can do this by simply clicking Sync Now at the top-right of the screen.</p>
<p>So now, the application is set up to work with the latest version of the AndroidX libraries and I can run the application to confirm that everything is still working.</p>
<h2 class="sectiontitle">Explore Android Jetpack Components</h2>
<p>The AndroidX libraries described previously are part of the Android Jetpack collection announced at the 2018 Google IO Conference. These are designed to speed up Android development.</p>
<p>Many of these libraries existed previously as part of the support libraries and we saw how to migrate over to AndroidX (and therefore to Jetpack). These are kept and maintained separately from the Android SDK in order to allow backward compatibility.</p>
<p>Some of these components are part of what are known as the Architecture components and these include the Lifecycles, Live Data, Navigation and Paging components and as well as speeding up development, these also help to ensure applications are easier to maintain.</p>
<p>If you put all of your functionality into a single activity, this is sometimes referred to as the ‘God Activity’ and this is not considered to be good practice. The architecture components encourage a development philosophy that supports a separation of concerns where each activity manages a distinct area of functionality such as dataset functionality, business logic, user interface management.</p>
<p>A more comprehensive description of these components is delivered in a course on Architecture Components.</p>
<p>In addition, there are some very specifically targeted components such as the Compatibility APIs for checking permissions, Notification APIs, APIs for Android Auto and so on. Becoming familiar with the Jetpack components is very important because Google are starting to focus on these as the preferred development methodology so that less code will be required to achieve the desired functionality.</p>
<p>The documentation along with a lot of additional supporting information can be found at https://developer.android.com/jetpack?hl=en.</p>
<h2 class="">Troubleshooting Android Studio Projects</h2>
<p>Android Studio is updated quite frequently so it is fairly common to open a file built with an older version. To illustrate this, and also to demonstrate how to resolve the issues that arise from this, we will open an older project.</p>
<p>From the Android Studio welcome screen, select Import an Android code sample as shown.</p>
<img src="images/figure10.png" alt="the Android Studio welcome screen from where we can import an Android code sample">
<p>In this case, we will filter for Kotlin and then scroll down to the Getting Started section and select </p>
<pre class="inset">
Basic sample (in Kotlin) for writing unit tests that mocks the framework</pre>
<p>We will shorten this name to BasicSample and click Finish to download the sample.</p>
<p>Note that when the program loaded, I immediately saw an error not shown on the video which indicated that the Gradle daemon had stopped for some reason. This is easily resolved by attempting to build the project and this restarts the Gradle daemon. Also perform any other updates which might be recommended.</p>
<p>Next, I can see two error conditions in the bottom right pane and these</p>
<img src="images/figure11.png" alt="two error conditions that appeared after the Gradle daemon was restarted">
<p>Clicking on the first link installs Build Tools 26.0.2 and I now get a new error message:</p>
<img src="images/figure12.png" alt="error that appears after installing Build Tools ">
<p>This error appears because this project’s Kotlin version does not match the version I currently have in Android Studio. To check the current version, from the File menu select Settings and then Plugins. Next, search for Kotlin and select the plugin (it may be necessary to ensure that the Installed tab is selected) and then click on the word Kotlin to obtain its installation details.</p>
<p>This shows that my Kotlin version number is 1.3.41 and when I call up the Gradle build file for the project, I can see that it has a Kotlin version number of 1.2.10 so I can manually change this to match the current version.</p>
<img src="images/figure13.png" alt="Another error!">
<p>Now that the Kotlin versions match, we can see another error. This is actually caused by an inconsistency between how Kotlin is declared compared to how it was declared in the past. This is fixed by going to the Gradle build file for the module. In this file, we have the dependencies as shown here:</p>
<pre class="inset">
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion"
// Unit testing dependencies.
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.8.9'
}</pre>
<p>The first line needs to be changed to:</p>
<pre class="inset">
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"</pre>
<p>Now, if we click Try Again at the top right, the project should build successfully and we can run it to confirm that this is the case.</p>
<p>At this point, if you still have some issues, there are a couple of other things you can try. Firstly, try rebuilding the project and this will delete any existing artefacts that have stale code in them and rebuilds the project from scratch. If this doesn’t solve the issue, click on the Gradle tab in the top right, right-click on the name of the project and select Refresh Gradle project.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='fundamentals .html';">
Android Development Fundamentals
</button>
<button class="button" onclick="window.location.href='gettingstarted.html';">
Getting Started
</button>
<button class="button" onclick="window.location.href='architecture.html'">
Android App Architecture
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,49 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2019</h2>
<h2 class="episodetitle">Android Development Fundamentals</h2>
</div>
<article>
<h2 class="sectiontitle">The History of Android</h2>
<p>Android is an OS based on Linux and designed to run on mobile platforms. In addition, it includes an application framework for the creation and deployment of apps that run on mobile devices and computers running the Chrome OS. Android apps can also be created for devices such as watches, TVs, IoT devices and so on.</p>
<p>The Android SDK provides tools to build, compile, test and deploy your apps and is typically exposed via Android Studio.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='gettingstarted.html';">
Getting Started
</button>
<button class="button" onclick="window.location.href='exploring.html';">
Exploring Android Projects
</button>
<button class="button" onclick="window.location.href='architecture.html'">
Android App Architecture
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,61 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2019</h2>
<h2 class="episodetitle">Getting Started</h2>
</div>
<article>
<h2 class="sectiontitle">Finding Answers in the Documentation</h2>
<p>Google provides a wealth of documentation including reference materials, tutorials, design guidelines and so in the online <a href="https://developer.android.com/docs">Developers Documentation</a>.</p>
<p>The reference section is separated into categories.</p>
<p class="inset">
• Android platform provides information on the classes and components that are part of the core API.
• Android Support Library provides information on components that are delivered separately.
• AndroidX contains information on many of the same packages found in the Android Support Library, but here they are split into different packages that start with the phrase “AndroidX”.</p>
<p>The easiest way to find information relating to a specific class is to type that class name into the search box.</p>
<p>As an example, we might search for Activity which is one of the most important classes in the SDK and then click through to android.app.activity. From here, note that we can use a drop-down box to select different API levels. Currently the default (that is, the highest) is level 29 and I notice that the documentation also defaults to Java but allows you to switch to Kotlin.</p>
<p>For the API level, the main point to note here is that if you select an older level, you will filter out classes and components so you will only see those which are available for the level you have selected.</p>
<p>Note that this feature doesn’t appear in the Android Support Library because the support library works across all versions of Android.</p>
<p>To some degree, the documentation is directly accessible from within Android Studio. If you select a class or component that is part of the core SDK, you can press Shift and F1 and this will take you to the external documentation. This does not work so well for classes that are part of the Support Library or AndroidX and you will often find that if you press Shift and F2 here, you won’t get any response.</p>
<p>However, there is an alternative keyboard shortcut which will give you some documentation. If you select a component such as AppCompatActivity and press Control and Q, a pop up will appear showing you the package that this is a member of. Pressing it again opens a separate window, pressing it again moves to the other tab and pressing it again closes the window.</p>
<p>We can use this same shortcut for classes where we do have full documentation and we will see much more information and again, we can cycle through the views by repeating the key press.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='fundamentals .html';">
Android Development Fundamentals
</button>
<button class="button" onclick="window.location.href='exploring.html';">
Exploring Android Projects
</button>
<button class="button" onclick="window.location.href='architecture.html'">
Android App Architecture
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2020</h2>
<h2 class="episodetitle">Analyze and Debug Your Code</h2>
</div>
<article>
<h2 class="sectiontitle"></h2>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='explore.html';">
Explore the User Interface
</button>
<button class="button" onclick="window.location.href='manage.html';">
Manage Project Builds and Dependencies
</button>
<button class="button" onclick="window.location.href='create.html'">
Create and Edit Code Files
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,36 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Studio Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2020</h2>
</div>
<article class="contents-article">
<section class="main_grid">
<div><a class="tile" href="explotre.html">Chapter 1 - Explore the User Interface</a></div>
<div><a class="tile" href="manage.html">Chapter 2 - Manage Project Builds and Dependencies</a></div>
<div><a class="tile" href="create.html">Chapter 3 - Create and Edit Code Files</a></div>
<div><a class="tile" href="analyze.html">Chapter 4 - Analyze and Debug Your Code</a></div>
<div><a class="tile" href="/android/android.html">Android Page</a></div>
<div><a class="tile" href="/index.html">Home</a></div>
</section>
</article>
</body>
</html>

@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2020</h2>
<h2 class="episodetitle">Create and Edit Code Files</h2>
</div>
<article>
<h2 class="sectiontitle"></h2>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='explore.html';">
Explore the User Interface
</button>
<button class="button" onclick="window.location.href='manage.html';">
Manage Project Builds and Dependencies
</button>
<button class="button" onclick="window.location.href='analyze.html'">
Analyze and Debug Your Code
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2020</h2>
<h2 class="episodetitle">Explore the User Interface</h2>
</div>
<article>
<h2 class="sectiontitle">Use Android Studio Tools Windows</h2>
<p>The Tools window can be accessed in several ways for example by </p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='manage.html';">
Manage Project Builds and Dependencies
</button>
<button class="button" onclick="window.location.href='create.html'">
Create and Edit Code Files
</button>
<button class="button" onclick="window.location.href='analyze.html'">
Analyze and Debug Your Code
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Android Development Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : August 2020</h2>
<h2 class="episodetitle">Manage Project Builds and Dependencies</h2>
</div>
<article>
<h2 class="sectiontitle"></h2>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='explore.html';">
Explore the User Interface
</button>
<button class="button" onclick="window.location.href='create.html'">
Create and Edit Code Files
</button>
<button class="button" onclick="window.location.href='analyze.html'">
Analyze and Debug Your Code
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,87 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Additional Notes</h2>
</div>
<article>
<h2 class="sectiontitle">if Expressions</h2>
<p>There are some useful videos on YouTube created by Peter Somerhoff and it is well worth subscribing to his channel. In particular, there are a couple of tutorial playlists of Lotlin tutorials.</p>
<pre class="inset">
<a href="https://youtu.be/AcwzpPLV5HY">Kotlin Tutorial</a> - 22 videos.
<a href="https://youtu.be/YpD3k22C-8Q">Kotlin for Android and Java Developers</a> - 12 videos.</pre>
<p>These notes are from video 5 in the Kotlin for Android and Java Developers playlist.</p>
<p>The Android Studio provides a facility that may be quite useful when developing code and that is the Kotlin REPL (REPL stands for Read-Eval-Print-Loop). This can be accessed via the Tools menu by selecting first Kotlin and then Kotlin REPL and this opens up a small integrated command line at the bottom of the screen. It should have a tab labelled something like Kotlin REPL (in module app) where app will be the name of your project and you may have to select it.</p>
<p>Here, you can type in Kotlin code a line at a time and it is interpreted in much the same way as Python would be if using a command line interface or IDLE in interpreter mode.</p>
<p>Another interesting point is really expanding on a point made in the section here entitled “Evaluate Conditions With If and Else” which mentions the fact that you can combine an assignment expression with an if statement. The video takes this a little further and notes that for any block of code in an if/if else/else block, the last statement returns the value for the assignment and this can be a simple expression such as a string or a variable name.</p>
<pre class="inset">
val i=17
val x=if (i &lt; 15) {
println("i is pretty small")
"small"
} else if (i &gt;=15 &amp;&amp; i &lt;= 25) {
println("it's okay")
"medium"
} else {
println("it's pretty large")
"large"
}</pre>
<p>The result of executing this code is that the string “it’s okay” is printed. We don’t print the value of x here but we can print this after the code has executed and we can see that the value “medium” has been assigned to it.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,68 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Appendix B - Useful Resources</h2>
</div>
<article>
<p>The online Android Developer Guides can be quite useful, particularly because they are the most up-to-date learning resources and they can be found at: <a href="https://developer.android.com/guide">https://developer.android.com/guide</a>.</p>
<p>The Google Developers homepage can be a useful resource for news relating to Android and Kotlin as well (since Kotlin is recognised officially by Google as a development language for Android Apps. This can be found at: <a href="https://developers.google.com/">https://developers.google.com/</a>.</p>
<p>The online documentation and reference for Kotlin is probably more important that, for instance, online documentation for Java since the language is still quite new and changing quite rapidly. This can be found at: <a href="https://kotlinlang.org/docs/reference/">https://kotlinlang.org/docs/reference/</a>.</p>
<p>For a quick experiment with Kotlin syntax, you can use the online compiler which is found at: <a href="https://repl.it/languages/kotlin">https://repl.it/languages/kotlin</a></p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,575 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Chapter 5 - Create Custom Classes</h2>
</div>
<article>
<h2 class="sectiontitle">Create a Library of Functions</h2>
<p>It is important to remember that Kotlin is a fully functional language and allows a complex program to be broken into many different smaller and more manageable classes.</p>
<p>One of the simplest uses of a class in Kotlin is to manage collections of functions which would be static functions in Java since they are meant to be called from a class rather than an instance of a class. Since Kotlin does not have the concept of static class members, functions and variables which are meant to be called from a class become part of a companion object.</p>
<p>For this example, we are starting out with a Kotlin file containing two functions, the main() function and a function called addValues() that takes two numbers as arguments and returns the result of adding the two together. This is fine if we only want to use the addValues() function within this file but if we want it to be available anywhere, it is better to put it into a separate class.</p>
<figure>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
try {
print("Number 1: ")
val string1: String? = readLine()
val number1 = string1!!.toDouble()
print("Number 2: ")
val string2 = readLine()
val number2 = string2!!.toDouble()
val result: Double? = addValues(number1, number2)
println("The answer is $result")
} catch (e: NumberFormatException) {
println("${e.message} is not a number")
} catch (e: Exception) {
println(e.message)
}
}
fun addValues(number1: Double, number2: Double) = number1 + number2</pre>
<figcaption>Figure 56 - our file with main() and addValues() functions</figcaption>
</figure>
<p>We will create a new class by right-clicking the source folder and selecting new and then selecting New Kotlin File/Class. In this case, we will give it the name MathLib and select class rather than file from the drop down menu.</p>
<p>Now, if we take the code for addValues() and place it inside the companion object, the class this gives us is shown in figure 57.</p>
<figure>
<pre class="inset">
class MathLib {
companion object {
fun addValues(number1: Double, number2: Double) = number1 + number2
}
}</pre>
<figcaption>Figure 57 - the MathLib class with one function (addValues()) defined within the companion object</figcaption>
</figure>
<p>Originally, we had called the addValues() function simply with:</p>
<pre class="inset">
val result: Double? = addValues(number1, number2)</pre>
<p>Now, to call it from the MathLib class, we simply change this to:</p>
<pre class="inset">
val result: Double? = MathLib.addValues(number1, number2)</pre>
<p>Note that we are using a bit of code to allow the user to input the first number and then an almost identical bit of code for the second number. We might want to convert this to a function to avoid repetition and we can do this in IntelliJ by selecting the three lines of code used to get the first number, right-clicking and selecting Refactor followed by Extract and then finally function. We will call it getNumber and this converts the three lines to a single line calling the function:</p>
<pre class="inset">
val number1 = getInput()</pre>
<p>It also generates the required function which can be seen in figure 58.</p>
<figure>
<pre class="inset">
private fun getInput(): Double {
print("Number 1: ")
val string1: String? = readLine()
val number1 = string1!!.toDouble()
return number1
}</pre>
<figcaption>Figure 58 - the getInput() function</figcaption>
</figure>
<p>We want to use this function to input both numbers so the prompt will have to change. Since the prompt will not be the same each time the function is called, we will have the code that calls the function supply a prompt which getInput() will display. We will also generalise the variable names giving us the modified version of the function as shown in figure 59.</p>
<figure>
<pre class="inset">
private fun getInput(prompt: String): Double {
print(prompt)
val string: String? = readLine()
val number = string!!.toDouble()
return number
}</pre>
<figcaption>Figure 59 - modified version of the getInput() function</figcaption>
</figure>
<p>This code can be copied into the MathLib class (removing the private keyword so that the functions scope becomes public) and we can now rewrite the main class as shown in figure 60.</p>
<figure>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
try {
val number1 = MathLib.getInput("Number 1")
val number2 = MathLib.getInput("Number 2")
val result: Double? = MathLib.addValues(number1, number2)
println("The answer is $result")
} catch (e: NumberFormatException) {
println("${e.message} is not a number")
} catch (e: Exception) {
println(e.message)
}
}</pre>
<figcaption>Figure 60 - the rewritten main() function</figcaption>
</figure>
<p>So now we can see that the main() function is much smaller. The saving in terms of lines of code is not significant here because it is a small sample program but we can now use these functions as many times as we want with a simple function call. More significantly, the class can be added to any new project so we can use the functions again without re-writing them and this would be particularly useful if the function were larger and more complex.</p>
<h2 class="sectiontitle">Create a Class with Instance Members</h2>
<p>We can create classes with methods and attributes just as we do in Java and these are public by default. It is not necessary to produce getters and setters but these can be added if needed and we can also restrict field visibility with modifier keywords. </p>
<p>For this example, we are using the MathLib class from the previous section. We will start by adding a variable to the MathLib class and this is outside of the companion object and is a Double value called runningTotal. Its value will change so it is declared as var and is initialised with 0.0. </p>
<p>Next, we will add a function called addValue() which will take one argument called value of type Double and it will add it to runningTotal. So now, if we create an instance of MathLib, it will have a variable called runningTotal which will persist for the lifetime of that instance. </p>
<p>Now, if we want to call methods belonging to the class, we will need an instance of the class and we can do that using the class constructor. Like Java, there is a Miranda constructor so we don’t need to create one. </p>
<p>In the main class, we are removing all the code we previously had in the try block and instead, creating our instance of MathLib which we will call mathLib. The syntax for this is:</p>
<pre class="inset">
val mathLib = MathLib()</pre>
<p>Note that unlike Java, we don’t need the keyword new. </p>
<p>Next, we will create an infinite loop within our try block that asks the user for a number and adds it to the running total. </p>
<figure>
<pre class="inset">
while(true){
val number: Double = MathLib.getInput("Enter a number: ")
mathLib.addValue(number)
println("Current total: ${mathLib.runningTotal}")
}</pre>
<figcaption>Figure 61 - the while loop used to calculate the running total</figcaption>
</figure>
<p>This code is shown in figure 61. Now, as with Java, the JVM does not calculate floating point numbers precisely so at some point, you may see that the result is actually off by a thousandth or a millionth. In Kotlin, we can help to remove this problem by using a BigDecimal value. We do this by amending the code in our getInput() function inside the MathLib class. Specifically, we want to change these lines: </p>
<pre class="inset">
val number = string!!.toDouble()
return number</pre>
<p>Here, we are taking a string and converting it to a Double value and then returning that same value. Instead, we want to change it to a BigDecimal value but we still want to return a Double so we will then convert the value we are returning to a Double so these lines become: </p>
<pre class="inset">
val number = string!!.toBigDecimal()
return number.toDouble()</pre>
<p>This also neatly demonstrates the advantage of using a class like this to encapsulate functionality. We have encountered a problem with our code but since it is isolated in the class, we only have to fix it in one place. The external operation of the function has not changed so any other code that uses this function will be unaffected.</p>
<h2 class="sectiontitle">Manage Value Lists with Enums</h2>
<p>Previously, we created constants as members of a companion object.</p>
<figure>
<pre class="inset">
class MathLib {
companion object {
const val ADD = "+"
const val SUBTRACT = "-"
const val MULTIPLY = "*"
const val DIVIDE = "/"
const val OPERATIONS = "+ - * /"
fun addValues(number1: Double, number2: Double) = number1 + number2
fun subtractValues(number1: Double, number2: Double) = number1 - number2
fun multiplyValues(number1: Double, number2: Double) = number1 * number2
fun divideValues(number1: Double, number2: Double) = number1 / number2
fun getInput(prompt: String): Double {
print(prompt)
val string: String? = readLine()
val number = string!!.toBigDecimal()
return number.toDouble()
}
}
}</pre>
<figcaption>Figure 62 - a companion object which creates constants for the literal strings used in the calculator example</figcaption>
</figure>
<p>Recall that in the calculator challenge, we used string literals for the operators. In figure 62, we have replaced these with constants declared in the MathLib class. Note that if we are using these constants in another class, we can hold down the control key and click on them and this will take us to the point in the MathLib class where they are declared.</p>
<p>In essence, we have a group of operators which are related but each have their distinct characteristics. Another way to deal with these would be to declare them in an Enum class or an enumeration. This can be nested class or it can be added to the same file as another class. Another option, which we will use here, is to declare it in its own separate class.</p>
<p>We will add the class in the same way as we added the MathLib class, but in the drop down menu we will select Enum Class as shown in figure 63.</p>
<figure>
<img src="images/figure63.png" alt="">
<figcaption>Figure 63 - creating an Enum Class</figcaption>
</figure>
<p>In Java, an enum is created simply using the keyword enum but since it is a type of class in Kotlin, it is declared as an emum class as seen in figure 64.</p>
<figure>
<pre class="inset">
enum class Operation {
}</pre>
<figcaption>Figure 64 - the code for our newly created Enum Class which we called Operation</figcaption>
</figure>
<p>Within the enum, we can now declare our four operators. Next, we want to add a pair of brackets after the class name and give it a String operator and after each of the values in our enumerator, we will define that string.</p>
<figure>
<pre class="inset">
enum class Operation(val operator: String){
ADD("+"), SUBTRACT("-"), MULTIPLY("*"), DIVIDE("/")
}</pre>
<figcaption>Figure 65 - the Operation enum class with each operator identified</figcaption>
</figure>
<p>Figure 65 shows the code for the enum class and this allows to now tidy up our code somewhat. In the MathLib.class, we can take away the constants which we no longer need.</p>
<p>In main, where we had lines such as:</p>
<pre class="inset">
MathLib.ADD -&gt; MathLib.addValues(number1, number2)</pre>
<p>which made use of the constants, we can now modify this to:</p>
<pre class="inset">
Operation.ADD.operator -&gt; MathLib.addValues(number1, number2)</pre>
<p>Figure 66 shows the when block with these modifications completed.</p>
<figure>
<pre class="inset">
when (operation) {
Operation.ADD.operator -&gt; MathLib.addValues(number1, number2)
Operation.SUBTRACT.operator -&gt; MathLib.subtractValues(number1, number2)
Operation.MULTIPLY.operator -&gt; MathLib.multiplyValues(number1, number2)
Operation.DIVIDE.operator -&gt; MathLib.divideValues(number1, number2)
else -&gt; throw Exception("Unknown operation")
}</pre>
<figcaption>Figure 66 - the modified when block</figcaption>
</figure>
<p>We can further streamline this by adding an import statement to our main class:</p>
<pre class="inset">
import Operation.*</pre>
<p>The completed classes are shown in figures 67 to 69.</p>
<figure>
<pre class="inset">
import Operation.*
fun main(args: Array&lt;String&gt;) {
try {
val number1 = MathLib.getInput("Number 1: ")
val number2 = MathLib.getInput("Number 2: ")
print("Select an operation (${MathLib.OPERATIONS}): ")
val operation = readLine()
val result: Double? =
when (operation) {
ADD.operator -&gt; MathLib.addValues(number1, number2)
SUBTRACT.operator -&gt; MathLib.subtractValues(number1, number2)
MULTIPLY.operator -&gt; MathLib.multiplyValues(number1, number2)
DIVIDE.operator -&gt; MathLib.divideValues(number1, number2)
else -&gt; throw Exception("Unknown operation")
}
println("The answer is $result")
} catch (e: NumberFormatException) {
println("${e.message} is not a number")
} catch (e: Exception) {
println(e.message)
}
}</pre>
<figcaption>Figure 67 - the completed Main class</figcaption>
</figure>
<figure>
<pre class="inset">
class MathLib {
companion object {
const val OPERATIONS = "+ - * /"
fun addValues(number1: Double, number2: Double) = number1 + number2
fun subtractValues(number1: Double, number2: Double) = number1 - number2
fun multiplyValues(number1: Double, number2: Double) = number1 * number2
fun divideValues(number1: Double, number2: Double) = number1 / number2
fun getInput(prompt: String): Double {
print(prompt)
val string: String? = readLine()
val number = string!!.toBigDecimal()
return number.toDouble()
}
}
}</pre>
<figcaption>Figure 68 - the completed MathLib class</figcaption>
</figure>
<figure>
<pre class="inset">
enum class Operation(val operator: String){
ADD("+"), SUBTRACT("-"), MULTIPLY("*"), DIVIDE("/")
}</pre>
<figcaption>Figure 69 - the completed Operation enum class</figcaption>
</figure>
<p>So, enumerations and constants allow you to set values in a way the complier recognizes but can also help to reduce spellings like duplication of values, misspellings and other bugs.</p>
<h2 class="sectiontitle">Declare and Use a Data Class</h2>
<p>In an object oriented language, classes are often used to manage data objects and such classes are sometimes called POJOs (Plain Old Java Objects) or sometimes Java Beans or Data Transfer Objects. Kotlin has a specific type of class for this type of functionality and it is called a data class.</p>
<p>To demonstrate this we are stating with an empty main function and we will add a class in the usual way, selecting class from the drop down menu. To change it to a data class we simply put the word data before class but notice that if this is done before anything else is added to the class, an error will appear.</p>
<figure>
<img src="images/figure70.png" alt="">
<figcaption>Figure 70 - a newly created data class with an error!</figcaption>
</figure>
<p>The error is shown in figure 70 and the reason we are seeing this is because of a requirement of the data class – it must have at least one field. Typically, you declare a data class’ fields as part of the class declaration, in the primary constructor.</p>
<p>We do this by putting the data items in brackets after the class name and these are delimited, if necessary, with a comma.</p>
<figure>
<pre class="inset">
data class ClothingItem(val type: String,
val size: String,
val price: Double) {
}</pre>
<figcaption>Figure 71 - the data class with three data fields added</figcaption>
</figure>
<p>This is shown in figure 71. By calling this a data class, we are getting some free functionality such as a toString() method. In addition, if we don’t need explicit getters and setters, we don’t need to implement these.</p>
<p>Now, our class has a body with no code in it so we can also remove this.</p>
<p>To use the class, we can go back to main and create an instance of ClothingItem with its primary constructor.</p>
<figure>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
val shirt = ClothingItem("Shirt", "Medium", 9.99)
println(shirt)
shirt.price=4.99
print(shirt.toString())
}</pre>
<figcaption>Figure 72 - the main function making use of the ClothingItem data class</figcaption>
</figure>
<p>Looking at the code in figure 72, we can see that an object has been created and displayed, the price has then been updated and the item displayed again. However, this gives us an error when we try to amend the price because in the data class, price (as with the other items) has been declared immutable so we need to amend that to allow this code to work.</p>
<p>Note, in addition, that I have displayed the item using a simple print method and then using print in conjunction with the toString() method but in either case, the result is the same. In both cases, the toString() method is being called and we can see this quite clearly if we override the method as shown in figure 73.</p>
<figure>
<pre class="inset">
override fun toString(): String {
return ("The item is a $type of size $size and costs £$price")
}</pre>
<figcaption>Figure 73 - the overridden toString() function</figcaption>
</figure>
<p>Now, when we run the code, we see that the item is printed twice and in both cases, it uses the new method so from this we can see that a statement such as:</p>
<pre class="inset">
println(shirt)</pre>
<p>although it doesn’t explicitly call the toString() function, does create an implicit call to the function.</p>
<h2 class="sectiontitle">Use Primary and Secondary Constructors</h2>
<p>As with Java, we can create several constructors with different argument lists, but unlike in Java, not all constructors are created equal. Every Kotlin class has a primary constructor defined by the class declaration with the list of parameters defining this constructor. This can be made explicit by placing the keyword constructor before the parameter list but this does not affect how it executes.</p>
<p>The primary constructor does not have an implementation block. If you add a code block after the class definition, that block contains all the code for the class, not just code that is executed when the constructor is called. If you want a block of code that executes when the constructor is called, you would put the required code into an init block.</p>
<p>To demonstrate this, let’s say that we want our constructor to automatically convert the type to uppercase. To do this, we will add an init block to do the conversion and this gives us an amended ClothingItem class as shown in figure 74. Note that type had previously been immutable so the code has also been amended to allow us to update the value.</p>
<figure>
<pre class="inset">
data class ClothingItem(var type: String,
val size: String,
var price: Double) {
init {
type = type.toUpperCase()
}
}</pre>
<figcaption>Figure 74 - the ClothingItem class amended so that we can execute some additional code when the constructor is called</figcaption>
</figure>
<p>To define a secondary constructor, we will add a constructor block to the ClothingItem class. Note that a secondary constructor must daisy-chain with the primary constructor.</p>
<figure>
<pre class="inset">
constructor(size: String, price: Double) : this(type: null, size, price)</pre>
<figcaption>Figure 75 - a secondary constructor</figcaption>
</figure>
<p>The secondary constructor is shown in figure 75 and there are a couple of important points to note here. Firstly, after the parameter list we have the special function called this which is calling the primary constructor.</p>
<p>Secondly, we are passing a null value for type to the primary constructor and this gives us a sequence of errors:</p>
<p class="inset">
• The first error is that type is not nullable so we will simply fix this by changing it to nullable in the original constructor as follows
o var type: String?
• This in turn causes an error because we are converting type to uppercase in the init block but because of our modifications, type might now be null. To fix this, we must either use a safe call or assert that type is not null. To make our call a safe call, we will amend the code in init to
o type = type?.toUpperCase()
So now if type is null, the code will not be executed.</p>
<p>To create the constructor, we have not only added the code for it but also made an amendment to the primary constructor so to recap, the amended ClothingItem class is shown in figure 76.</p>
<figure>
<pre class="inset">
data class ClothingItem(var type: String?,
var size: String,
var price: Double) {
init {
type = type?.toUpperCase()
}
constructor(size: String, price: Double) : this(type: null, size, price)
}</pre>
<figcaption>Figure 76 - the amended ClothingItem class</figcaption>
</figure>
<p>If we go back to the main function, we can now create a new object which we will call newItem with:</p>
<pre class="inset">
val newItem = ClothingItem(size="Large", price=14.99)</pre>
<p>Aside, if we type in this line as far as ClothingItem() we can then press Control and P in order to see a list of the available signatures.</p>
<p>We can print this off as well and we will see the type shown as null.</p>
<p>There are a couple of points which must be made about the secondary constructor. Notice that the parameter list is just:</p>
<pre class="inset">
(null, size, price)</pre>
<p>We don’t need to declare these as val or var since this declaration happens in the primary customer. Also, it may be tempting to type the name of the variable, type so you have:</p>
<pre class="inset">
(type: null, size, price)</pre>
<p>but this will give us an error. We simply type null in place of the type variable and the IDE adds in the identifier.</p>
<p>Unlike a primary constructor, a secondary constructor can have an implementation block so we could use this to give the type a more descriptive value than simply showing it as null.</p>
<p>This gives us an amended secondary constructor as shown in figure 77.</p>
<figure>
<pre class="inset">
constructor(size: String, price: Double) : this (null, size, price) {
type = "Unknown"
}</pre>
<figcaption>Figure 77 - the secondary constructor with an added implementation block</figcaption>
</figure>
<p>Of course, this is not the only way to fix the description for type when it has a value of null. As an alternative, we might fix this in the init block using an Elvis operator. We already have a line of code to convert type to upper case but it does nothing if type is null so we can use the Elvis operator to provide the required alternative and this gives us an amended init block as shown in figure 78.</p>
<figure>
<pre class="inset">
init {
type = type?.toUpperCase() ?: "Unknown"
}</pre>
<figcaption>Figure 78 - the amended init block</figcaption>
</figure>
<p>As with Java, you can have as many constructors as you like provided that each has a unique signature. However, unlike Java, where chaining constructors together is considered to be best practice, in Kotlin it is a requirement.</p>
<h2 class="sectiontitle">Use Explicit Getter and Setter Functions</h2>
<p>You can create Kotlin getter and setter functions that work as class properties for any fields declared in the class body. You can’t create them for fields declared as part of the primary constructor.</p>
<p>To demonstrate this, we will use our ClothingItem class and start by renaming the variable we had called type which we will now call _type and declare it as private. We will also make changes to the variable in the init block and the code works just as it did previously.</p>
<p>Now, if we remove (or comment out) the init block and run the code again, we can see that the item created with the secondary constructor is again showing its type as null. </p>
<p>Still in the ClothingItem class, we will now add another data item called type and we will create a getter method that goes right after the variable declaration. If we only need a simple calculation, we can simply assign the value with an equals operator or we can put in a full code block. In this case, we want to return either the value of the type field or “unknown” so we just need to assign this with the Elvis operator.</p>
<p>To access the field, we use the keyword field so this gives us a setter method as shown in figure 79 (along with the variable declaration).</p>
<figure>
<pre class="inset">
var type: String? = _type
get() = field ?: "Unknown"</pre>
<figcaption>Figure 79 - the declaration of our public type field along with its getter method</figcaption>
</figure>
<p>If we run the code again, we can see that our item type still shows as null but the main point here is that we can access this via the getter method with something like: </p>
<pre class="inset">
println("Item type - ${newItem.type}")</pre>
<p>Setter methods follow a similar pattern and we will demonstrate this with the price field. As before, we will change the name to _price and declare it as private. We will then declare a public variable called price and create a setter method right after it, using a code block this time.</p>
<figure>
<pre class="inset">
var price = _price
set (value) {
field = value * .9
}</pre>
<figcaption>Figure 80 - the price field with its setter method</figcaption>
</figure>
<p>This is shown in figure 80 with value being the value sent to the setter method and again, the keyword field used to reference the field. Note that the value passed in is then multiplied by 0.9 rather than simply being assigned, effectively creating a 10% discount.</p>
<p>We can test this with a snippet of code as shown in figure 81.</p>
<figure>
<pre class="inset">
newItem.price = 10.00
println("NewItem price = ${newItem.price}")</pre>
<figcaption>Figure 81 - code testing the setter method we created for price</figcaption>
</figure>
<p>Notice, here, we have assigned the price for newItem as 10.00 and then printed it out and as expected, the price displayed is 9.00 – the 10% discount has been applied!</p>
<p>As was hinted previously, we can use a getter to deliver a calculated result and we will demonstrate this by adding a new data class to our application called Person. In the class, we will declare two private string variables in the primary constructor (firstName and lastName) and another public variable called fullName. Along with fullName, we will also have a getter method that returns, as you might expect, firstName followed by lastName. This class is show in figure 82.</p>
<figure>
<pre class="inset">
data class Person (private val firstName: String,
private val lastName: String) {
var fullName: String =""
get() = "$firstName $lastName"
}</pre>
<figcaption>Figure 82 - the Person data class</figcaption>
</figure>
<p>Side note – notice that the variable fullName has been initialised with an empty string. The code demonstrated on the video omitted this but I got an error when I copied that code stating that an initialisation was required and so this is why it appears here.</p>
<p>In figure 83, there is a snippet of code used to create a Person object with a firstName and a lastName followed by a line of code to print out the fullName.</p>
<figure>
<pre class="inset">
val p1 = Person("Philip", "Osztromok")
println(p1.fullName)</pre>
<figcaption>Figure 83 - code to test our Person class and particularly the getter method for the fullName variable</figcaption>
</figure>
<p>In Kotlin, getters and setters allow us to encapsulate data management logic in our Kotlin classes, making for more readable, maintainable code.</p>
<h2 class="inset">Mix and Match Java Classes</h2>
<p>When working in Kotlin, you might want to have access to some functionality which is available in Java but not in Kotlin. Fortunately, when you are working with Kotlin in a JVM environment (including when creating android apps)you have access to the entire Java core runtime.</p>
<p>To see how this works, let’s assume we want to display the price of a ClothingItem (using our previous example) as a neatly formatted currency amount.</p>
<p>First of all, let’s see how we would do this using Kotlin only. Kotlin does not have a native currency formatting function but we can come close with some simple string formatting.</p>
<p>We start by creating a variable which we will call f (for format) and we will initialise it as:</p>
<pre class="inset">
val f = "%.2f"</pre>
<p>This means that there are two numbers after the decimal point.</p>
<p>The line we are currently using to display the price is:</p>
<pre class="inset">
println("NewItem price = ${newItem.price}")</pre>
<p>and we will change this to:</p>
<pre class="inset">
println("Item price = ${f.format(newItem.price)}")</pre>
<p>So in our string here, we are using the value f, sending it a format message with the price attribute of newItem as its parameter and this returns our neatly formatted currency value. If we also want a currency symbol we can put this in front of the $ we already have. This can be a second dollar sign if we want to show the value in dollars or it could be, for example, a £ sign.</p>
<p>The drawback here is that the currency formatting is hard-coded which would make it more difficult, for example, if we wanted to switch to a different currency.</p>
<p>As it happens, the Java localization libraries are really useful for this kind of coding so let’s look at how we would do this using the Java library.</p>
<p>We will, once again, starting by declaring a variable which we will call formatter and we will get its value with:</p>
<pre class="inset">
val formatter = NumberFormat.getCurrencyInstance()</pre>
<p>Note that IntelliJ adds the line:</p>
<pre class="inset">
import java.text.NumberFormat</pre>
<p>to the code to make this class accessible.</p>
<p>We can now print our currency value with the following:</p>
<pre class="inset">
println("Item price = ${formatter.format(newItem.price)}")</pre>
<p>Note that the currency symbol has been omitted. In addition, because my system locale is the UK, the default value is a £ sign so this is automatically showing the code as UK currency.</p>
<p>If we want to use a different currency and currency format (for example, in France the currency is the Euro and a comma is used rather than a full stop) we can use the following line of code:</p>
<pre class="inset">
Locale.setDefault(Locale.FRANCE)</pre>
<p>Obviously, we want to execute this code before we create the variable formatter and the result is that we will see our price displayed both in the currency used in France and in the format commonly used there as follows:</p>
<pre class="inset">
Item price = 9,00 €</pre>
<figure>
<img src="images/figure84.png" alt="">
<figcaption>Figure 84 - screenshot of the code taken from the course video</figcaption>
</figure>
<p>Figure 84 is a screenshot taken from the corresponding video in the LinkedIn Learning course. Note that the line creating the formatter variable also shows the data type inferred by the compiler which in this case is NumberFormat and is followed by an exclamation mark.</p>
<p>The exclamation mark denotes the fact that this class comes from the platform, in this case the JVM. Classes that do not have the exclamation mark come from the Kotlin standard library.</p>
<p>As it happens, I didn’t see this in my code which is why I have taken the screenshot but it is worth noting that the data type can be added to your own code simply by typing :NumberFormat after the variable name but you can’t add the exclamation mark, this is something the compiler does to show that it is an external class.</p>
<p>It is worth noting that this idea applies if you are working with Kotlin for Javascript or Kotlin native.</p>
<p>The main lesson to take from this is that although Kotlin is a great language, there will be times when there is a better solution to a particular problem available in, for example, the classes in the Java core runtime packages so you want to be sure you are selecting the best tools for a particular task.</p>
<h2 class="sectiontitle">Organise Your Classes with Packages</h2>
<p>As in Java, you can organise your Kotlin code in packages. But unlike Java, the package name does not have to match the directory in which the code is stored. </p>
<p>To show how this works, we will continue on with the ClothingItem example and we’ll start by declaring a package in the main class with the line: </p>
<pre class="inset">
package com.example.kotlin</pre>
<p>This generates a warning because of the fact that our package name does not match the directory structure and this is shown in figure 85. But this is not a restriction.</p>
<p>Figure 85 also shows the name of our ClothingItem class in red and this applies also to the Person class which is not shown here. This indicates that these classes are no longer accessible since the main class is now in a different package (or rather, it is in a package that does not contain the other two classes).</p>
<figure>
<img src="images/figure85.png" alt="">
<figcaption>Figure 85 - warning generated when we use a package directive that does not match the directory structure for our source code</figcaption>
</figure>
<p>We can easily fix this by adding the same package declaration to both the ClothingItem and the Person classes.</p>
<p>If we try to run the code now, we will see an error but this is not because of the code, it is actually because of the configuration of the IDE so we need to select the Run menu and then Edit Configurations.</p>
<figure>
<img src="images/figure86.png" alt="">
<figcaption>Figure 86 - the Edit Configurations menu accessible from the Run Menu</figcaption>
</figure>
<p>The panel shown in figure 86 then appears and this has been amended so that the name of the main class (MainKt) has been prepended with the package name, again using the reverse domain notation.</p>
<p>Note that at this point, the files themselves have not been moved, but in fact, IntelliJ makes it very easy to do this. We just need to move the cursor to the package name and use an intention action to ‘com/example/kotlin’ as shown in figure 87.</p>
<figure>
<img src="images/figure87.png" alt="">
<figcaption>Figure 87 - using an intention action to move the files into the com/example/kotlin directory.</figcaption>
</figure>
<p>This automatically creates the appropriate folder with the source code folder as can be seen in figure 88.</p>
<figure>
<img src="images/figure88.png" alt="">
<figcaption>Figure 88 - an Explorer window showing the automatically created folder structure</figcaption>
</figure>
<p>We can do this for all of our classes and as shown in figure 88, this has already been done and all our files are in the kotlin folder.</p>
<p>If you are building an Android app with Kotlin, this is the way in which you will organise your files. The base class package in Android matches the universal unique application ID and so you will create your files in the directory that matches the base class package.</p>
<p>To demonstrate this, we will use version control to revert to a previous version of the code and then edit the configuration file to remove the package name from the main class and the application still runs.</p>
<p>So, you can use this type of package structure for a Kotlin program, but you can also use packages in a different way. For instance, in this application, the Person and ClothingItem classes are model classes. If we want, we can create a package called model for these classes.</p>
<p>We will right-click on the source folder and select New and then package and give it the name model. We can then select both ClothingItem and Person in the navigation pane and drag and drop them into the new package.</p>
<figure>
<img src="images/figure89.png" alt="">
<figcaption>Figure 89 - the move dialog that appears when our files are dragged and dropped into the new model package</figcaption>
</figure>
<p>As we can see in figure 89, these are various options available when doing this but in order to complete the move we will click on refactor. This moves the files but also adds a package statement to each class and import statements to the main class so there are no manual changes required to ensure the application still runs.</p>
<p>It does!</p>
<p>Note that organising our files in this way means that we have a package declaration for each of the classes we have designated as model classes but not for the main class.</p>
<p>So this effectively gives us two ‘styles’ of file organisation. For a pure Kotlin application, the recommendation is that you should organise your files into packages that reflect their purpose, as we did with the model package.</p>
<p>For applications that mix Kotlin and Java, such as an Android app, you will use reverse domain notation for your base package and match the directory to the package.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,104 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Samples</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 1</h2>
<h3 class="subsectiontitle"><a href="code/0105.html" target="_blank">01_05</a></h3>
<h2 class="sectiontitle">Chapter 3</h2>
<h3 class="subsectiontitle"><a href="code/0105.html" target="_blank">03_01</a></h3>
<h3 class="subsectiontitle"><a href="code/0303.html" target="_blank">03_03</a></h3>
<h3 class="subsectiontitle"><a href="code/0304.html" target="_blank">03_04</a></h3>
<h3 class="subsectiontitle"><a href="code/0305.html" target="_blank">03_05</a></h3>
<h3 class="subsectiontitle"><a href="code/0306.html" target="_blank">03_06</a></h3>
<h3 class="subsectiontitle"><a href="code/0307.html" target="_blank">03_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0308.html" target="_blank">03_08</a></h3>
<h3 class="subsectiontitle"><a href="code/0309.html" target="_blank">03_09</a></h3>
<h2 class="sectiontitle">Chapter 4</h2>
<h3 class="subsectiontitle"><a href="code/0401.html" target="_blank">04_01</a></h3>
<h3 class="subsectiontitle"><a href="code/0402.html" target="_blank">04_02</a></h3>
<h3 class="subsectiontitle"><a href="code/0403.html" target="_blank">04_03</a></h3>
<h3 class="subsectiontitle"><a href="code/0404.html" target="_blank">04_04</a></h3>
<h3 class="subsectiontitle"><a href="code/0405.html" target="_blank">04_05</a></h3>
<h3 class="subsectiontitle"><a href="code/0406.html" target="_blank">04_06</a></h3>
<h3 class="subsectiontitle"><a href="code/0407.html" target="_blank">04_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0408.html" target="_blank">04_08</a></h3>
<h2 class="sectiontitle">Chapter 5</h2>
<h3 class="subsectiontitle"><a href="code/0501.html" target="_blank">05_01</a></h3>
<h3 class="subsectiontitle"><a href="code/0502.html" target="_blank">05_02</a></h3>
<h3 class="subsectiontitle"><a href="code/0503.html" target="_blank">05_03</a></h3>
<h3 class="subsectiontitle"><a href="code/0504.html" target="_blank">05_04</a></h3>
<h3 class="subsectiontitle"><a href="code/0505.html" target="_blank">05_05</a></h3>
<h3 class="subsectiontitle"><a href="code/0506.html" target="_blank">05_06</a></h3>
<h3 class="subsectiontitle"><a href="code/0507.html" target="_blank">05_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0508.html" target="_blank">05_08</a></h3>
<h2 class="sectiontitle">Chapter 6</h2>
<h3 class="subsectiontitle"><a href="code/0601.html" target="_blank">06_01</a></h3>
<h3 class="subsectiontitle"><a href="code/0602.html" target="_blank">06_02</a></h3>
<h3 class="subsectiontitle"><a href="code/0603.html" target="_blank">06_03</a></h3>
<h3 class="subsectiontitle"><a href="code/0604.html" target="_blank">06_04</a></h3>
<h2 class="sectiontitle">Chapter 7</h2>
<h3 class="subsectiontitle"><a href="code/0701.html" target="_blank">04_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0702.html" target="_blank">04_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0703.html" target="_blank">04_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0704.html" target="_blank">04_07</a></h3>
<h3 class="subsectiontitle"><a href="code/0705.html" target="_blank">04_07</a></h3>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='/android/kotlinessentialtraining/appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,76 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 1 - Section 5</h2>
<pre class="inset">
fun main(args: Array&lt;String\&gt;) {
println("Welcome to Kotlin Essential Training, ${args[0]}!")
println("The first argument is " + args[0])
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,82 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 1</h2>
<pre class="inset">
val myName = "David"
fun main(args: Array&lt;String&gt;) {
var num1 = 45.0
println("The initial value of num1 is $num1")
num1 ++
println("The new value of num1 is $num1")
val num2:Double = 5.toDouble()
println("The value of num2 is $num2")
println("My name is $myName")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,85 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 3</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
val myInt = 42
val myLong:Long = myInt.toLong()
println("the type of myLong is ${myLong::class.qualifiedName}")
val myLong2 = 42.9
var myInt2 = myLong2.toInt()
println("the value of myLong2 is $myLong2")
println("the value of myInt2 is $myInt2")
val myInt3 = 568
val myDouble3 = myInt3.toDouble()
println("the value of myDouble3 is $myDouble3")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,81 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 4</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
val num1 = 10
val num2 = 15
val match = (num1 == num2)
println("Match = $match")
val match2 = num1.equals(num2)
println("Match2 = $match2")
println("Comparison result = ${num1.compareTo(num2)}")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,91 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 5</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
var num1 = 15
val num2 = 10
val sum = num1 + num2
println("sum: $sum")
val sum2 = num1.plus(num2)
println("sum2: $sum2")
val diff = num1 - num2
println("diff: $diff")
num1 ++
println("num1: $num1")
val num3 = num1.inc()
println("num1: $num3")
println("the value of n1 = ${++num1}")
println ("num1=$num1")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,100 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 6</h2>
<pre class="inset">
import kotlin.math.*
//import java.lang.Math.abs
//import java.lang.Math.round
fun main(args: Array&lt;String&gt;) {
val num1 = 15
val num2 = 10
val sum = num1.plus(num2)
println("sum=$sum")
val difference = num1.minus(num2)
println("difference=$difference")
val product = num1.times(num2)
println("product=$product")
val quotient:Double = num1.toDouble().div(num2)
println("quotient=$quotient")
val remainder = num1.rem(num2)
println("remainder=$remainder")
val neg = -152.5
val absolute = abs(neg)
println("absolute=$absolute")
println("rounded=${round(absolute)}")
println("Have a piece of $PI")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,98 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 7</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
var aString = "Hello!"
println(aString)
val empty = String()
println("'$empty'")
val charArray = aString.toCharArray()
println(charArray.toList())
val byteArray = aString.toByteArray()
println(byteArray.toList())
aString += " and Welcome!"
println(aString)
val len = aString.length
for (i in 0 until len) {
val c = aString.get(i)
println(c)
}
val p = aString.indexOf("W")
val sub = aString.substring(p)
println(sub)
val string2 = aString.toUpperCase()
val match = aString.equals(string2, true)
println("Do they match? $match")
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 8</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
val builder = StringBuilder("To be or not to be\n")
.append("that is the question\n")
.append("Whether 'tis nobler in the mind\n")
.append("to suffer the slings and arrows")
val result = builder.toString()
println(result)
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,80 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 3 - Section 9</h2>
<pre class="inset">
import Constants.Companion.RED
fun main(args: Array&lt;String&gt;) {
println("the color is $RED")
}
class Constants {
companion object {
const val RED = "Red"
}
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

@ -0,0 +1,113 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/android/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink"><a href="https://www.linkedin.com/learning/kotlin-essential-training-2018">Kotlin Essential Training</a></h1>
<h2 class="lecturer">LinkedIn Learning : David Gassner : March 2018</h2>
<h2 class="episodetitle">Code Sample</h2>
</div>
<article>
<h2 class="sectiontitle">Chapter 4 - Section 1</h2>
<pre class="inset">
fun main(args: Array&lt;String&gt;) {
val num1 = 4.0
val num2 = 3.5
val result = addValues(param2 = num2, param1 = num1)
println("the result is $result")
val result2 = calcValues(num1, num2, "-")
println("Result 2 is $result2")
changeSomething(5.0)
val sum: Int = addValues(1, 3, 5, 7)
println("Sum=$sum")
}
fun addValues(param1: Double, param2: Double): Double {
return param1 + param2
}
fun calcValues(param1: Double, param2: Double, op: String = "+"): Double {
if (op.equals("+")) {
return param1 + param2
} else if (op.equals("-")) {
return param1 - param2
} else {
return -1.0
}
}
fun changeSomething(param: Double) {
// param ++
var copy = param
copy++
println("Copy is $copy")
}
fun addValues(vararg numbers: Int): Int {
var result = 0
for (i in numbers) {
result += i
}
return result
}</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='setting.html';">
Chapter 1
</button>
<button class="button" onclick="window.location.href='getstarted.html'">
Chapter 2
</button>
<button class="button" onclick="window.location.href='variables.html'">
Chapter 3
</button>
<button class="button" onclick="window.location.href='flow.html'">
Chapter 4
</button>
<button class="button" onclick="window.location.href='classes.html'">
Chapter 5
</button>
<button class="button" onclick="window.location.href='data.html'">
Chapter 6
</button>
<button class="button" onclick="window.location.href='inheritance.html'">
Chapter 7
</button>
<button class="button" onclick="window.location.href='appendixa.html'">
Appendix A
</button>
<button class="button" onclick="window.location.href='appendixb.html'">
Appendix B
</button>
<button class="button" onclick="window.location.href='code.html'">
Code Samples
</button>
<button class="button" onclick="window.location.href='/android/android.html'">
Android Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save